From 72c473693619814bce33d816af744341d96470f8 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Mon, 9 Mar 2009 15:44:11 -0500 Subject: [PATCH 01/17] Renaming an internal word in regexp --- basis/regexp/classes/classes-tests.factor | 26 +++++----- basis/regexp/classes/classes.factor | 52 ++++++++++++------- .../combinators/combinators-tests.factor | 2 +- basis/regexp/compiler/compiler.factor | 2 +- 4 files changed, 47 insertions(+), 35 deletions(-) diff --git a/basis/regexp/classes/classes-tests.factor b/basis/regexp/classes/classes-tests.factor index 520e23c749..2deb944b61 100644 --- a/basis/regexp/classes/classes-tests.factor +++ b/basis/regexp/classes/classes-tests.factor @@ -30,15 +30,15 @@ IN: regexp.classes.tests [ T{ or-class { seq { 3 2 } } } ] [ { 2 3 } 1 2array ] unit-test [ f ] [ t ] unit-test [ t ] [ f ] unit-test -[ f ] [ 1 1 t replace-question ] unit-test +[ f ] [ 1 1 t answer ] unit-test ! Making classes into nested conditionals [ V{ 1 2 3 4 } ] [ T{ and-class f { 1 T{ not-class f 2 } T{ or-class f { 3 4 } } 2 } } class>questions ] unit-test [ { 3 } ] [ { { 3 t } } table>condition ] unit-test [ { T{ primitive-class } } ] [ { { 1 t } { 2 T{ primitive-class } } } table>questions ] unit-test -[ { { 1 t } { 2 t } } ] [ { { 1 t } { 2 T{ primitive-class } } } T{ primitive-class } t answer ] unit-test -[ { { 1 t } } ] [ { { 1 t } { 2 T{ primitive-class } } } T{ primitive-class } f answer ] unit-test +[ { { 1 t } { 2 t } } ] [ { { 1 t } { 2 T{ primitive-class } } } T{ primitive-class } t assoc-answer ] unit-test +[ { { 1 t } } ] [ { { 1 t } { 2 T{ primitive-class } } } T{ primitive-class } f assoc-answer ] unit-test [ T{ condition f T{ primitive-class } { 1 2 } { 1 } } ] [ { { 1 t } { 2 T{ primitive-class } } } table>condition ] unit-test SYMBOL: foo @@ -46,13 +46,13 @@ SYMBOL: bar [ T{ condition f T{ primitive-class f bar } T{ condition f T{ primitive-class f foo } { 1 3 2 } { 1 3 } } T{ condition f T{ primitive-class f foo } { 1 2 } { 1 } } } ] [ { { 1 t } { 3 T{ primitive-class f bar } } { 2 T{ primitive-class f foo } } } table>condition ] unit-test -[ t ] [ foo dup t replace-question ] unit-test -[ f ] [ foo dup f replace-question ] unit-test -[ T{ primitive-class f foo } ] [ foo bar t replace-question ] unit-test -[ T{ primitive-class f foo } ] [ foo bar f replace-question ] unit-test -[ T{ primitive-class f foo } ] [ foo bar 2array bar t replace-question ] unit-test -[ T{ primitive-class f bar } ] [ foo bar 2array foo t replace-question ] unit-test -[ f ] [ foo bar 2array foo f replace-question ] unit-test -[ f ] [ foo bar 2array bar f replace-question ] unit-test -[ t ] [ foo bar 2array bar t replace-question ] unit-test -[ T{ primitive-class f foo } ] [ foo bar 2array bar f replace-question ] unit-test +[ t ] [ foo dup t answer ] unit-test +[ f ] [ foo dup f answer ] unit-test +[ T{ primitive-class f foo } ] [ foo bar t answer ] unit-test +[ T{ primitive-class f foo } ] [ foo bar f answer ] unit-test +[ T{ primitive-class f foo } ] [ foo bar 2array bar t answer ] unit-test +[ T{ primitive-class f bar } ] [ foo bar 2array foo t answer ] unit-test +[ f ] [ foo bar 2array foo f answer ] unit-test +[ f ] [ foo bar 2array bar f answer ] unit-test +[ t ] [ foo bar 2array bar t answer ] unit-test +[ T{ primitive-class f foo } ] [ foo bar 2array bar f answer ] unit-test diff --git a/basis/regexp/classes/classes.factor b/basis/regexp/classes/classes.factor index 8912082ec3..4ddd470189 100644 --- a/basis/regexp/classes/classes.factor +++ b/basis/regexp/classes/classes.factor @@ -163,20 +163,32 @@ M: integer combine-or : try-combine ( elt1 elt2 quot -- combined/f ? ) 3dup call [ [ 3drop ] dip t ] [ drop swapd call ] if ; inline +DEFER: answer + +:: try-cancel ( elt1 elt2 empty -- combined/f ? ) + [ elt1 elt2 empty answer dup elt1 = not ] try-combine ; + :: prefix-combining ( seq elt quot: ( elt1 elt2 -- combined/f ? ) -- newseq ) f :> combined! - seq [ elt quot try-combine swap combined! ] find drop + seq [ elt quot call swap combined! ] find drop [ seq remove-nth combined prefix ] [ seq elt prefix ] if* ; inline +: combine-by ( seq quot -- new-seq ) + { } swap '[ _ prefix-combining ] reduce ; inline + +:: seq>instance ( seq empty class -- instance ) + seq length { + { 0 [ empty ] } + { 1 [ seq first ] } + [ drop class new seq >>seq ] + } case ; inline + :: combine ( seq quot: ( elt1 elt2 -- combined/f ? ) empty class -- newseq ) seq class flatten - { } [ quot prefix-combining ] reduce - dup length { - { 0 [ drop empty ] } - { 1 [ first ] } - [ drop class new swap >>seq ] - } case ; inline + [ quot try-combine ] combine-by + ! [ empty try-cancel ] combine-by ! This makes the algorithm O(n^4) + empty class seq>instance ; inline : ( seq -- class ) [ combine-and ] t and-class combine ; @@ -218,36 +230,36 @@ UNION: class primitive-class not-class or-class and-class range ; TUPLE: condition question yes no ; C: condition -GENERIC# replace-question 2 ( class from to -- new-class ) +GENERIC# answer 2 ( class from to -- new-class ) -M:: object replace-question ( class from to -- new-class ) +M:: object answer ( class from to -- new-class ) class from = to class ? ; : replace-compound ( class from to -- seq ) - [ seq>> ] 2dip '[ _ _ replace-question ] map ; + [ seq>> ] 2dip '[ _ _ answer ] map ; -M: and-class replace-question +M: and-class answer replace-compound ; -M: or-class replace-question +M: or-class answer replace-compound ; -M: not-class replace-question - [ class>> ] 2dip replace-question ; +M: not-class answer + [ class>> ] 2dip answer ; -: answer ( table question answer -- new-table ) - '[ _ _ replace-question ] assoc-map +: assoc-answer ( table question answer -- new-table ) + '[ _ _ answer ] assoc-map [ nip ] assoc-filter ; -: answers ( table questions answer -- new-table ) - '[ _ answer ] each ; +: assoc-answers ( table questions answer -- new-table ) + '[ _ assoc-answer ] each ; DEFER: make-condition : (make-condition) ( table questions question -- condition ) [ 2nip ] - [ swap [ t answer ] dip make-condition ] - [ swap [ f answer ] dip make-condition ] 3tri + [ swap [ t assoc-answer ] dip make-condition ] + [ swap [ f assoc-answer ] dip make-condition ] 3tri 2dup = [ 2nip ] [ ] if ; : make-condition ( table questions -- condition ) diff --git a/basis/regexp/combinators/combinators-tests.factor b/basis/regexp/combinators/combinators-tests.factor index 0ba2831842..6690440345 100644 --- a/basis/regexp/combinators/combinators-tests.factor +++ b/basis/regexp/combinators/combinators-tests.factor @@ -16,7 +16,7 @@ USE: multiline { R' .*a' R' b.*' } ; [ t ] [ "bljhasflsda" conj matches? ] unit-test -[ f ] [ "bsdfdfs" conj matches? ] unit-test ! why does this fail? +[ f ] [ "bsdfdfs" conj matches? ] unit-test [ f ] [ "fsfa" conj matches? ] unit-test [ f ] [ "bljhasflsda" conj matches? ] unit-test diff --git a/basis/regexp/compiler/compiler.factor b/basis/regexp/compiler/compiler.factor index 4e615d15d7..23171b4636 100644 --- a/basis/regexp/compiler/compiler.factor +++ b/basis/regexp/compiler/compiler.factor @@ -64,7 +64,7 @@ C: box : non-literals>dispatch ( literals non-literals -- quot ) [ swap ] assoc-map ! we want state => predicate, and get the opposite as input - swap keys f answers + swap keys f assoc-answers table>condition [ ] condition-map condition>quot ; : literals>cases ( literal-transitions -- case-body ) From 6ccd58f2787a8367bdbbd73debce71f38fcc7306 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Mon, 9 Mar 2009 17:29:32 -0500 Subject: [PATCH 02/17] Making all the regexp words compile --- basis/regexp/compiler/compiler.factor | 14 ++++++++------ basis/regexp/regexp-tests.factor | 5 ++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/basis/regexp/compiler/compiler.factor b/basis/regexp/compiler/compiler.factor index 23171b4636..eedf05a81e 100644 --- a/basis/regexp/compiler/compiler.factor +++ b/basis/regexp/compiler/compiler.factor @@ -106,13 +106,15 @@ C: box transitions>quot ; : states>code ( words dfa -- ) - '[ + [ ! with-compilation-unit doesn't compile, so we need call( -- ) [ - dup _ word>quot - (( last-match index string -- ? )) - define-declared - ] each - ] with-compilation-unit ; + '[ + dup _ word>quot + (( last-match index string -- ? )) + define-declared + ] each + ] with-compilation-unit + ] call( words dfa -- ) ; : states>words ( dfa -- words dfa ) dup transitions>> keys [ gensym ] H{ } map>assoc diff --git a/basis/regexp/regexp-tests.factor b/basis/regexp/regexp-tests.factor index 0a448ed276..99cb8dbd22 100644 --- a/basis/regexp/regexp-tests.factor +++ b/basis/regexp/regexp-tests.factor @@ -5,9 +5,8 @@ eval strings multiline accessors regexp.matchers ; IN: regexp-tests \ must-infer -! the following don't compile because [ ] with-compilation-unit doesn't compile -! \ compile-regexp must-infer -! \ matches? must-infer +\ compile-regexp must-infer +\ matches? must-infer [ f ] [ "b" "a*" matches? ] unit-test [ t ] [ "" "a*" matches? ] unit-test From ff3c5b28bdc5e1206cc4a16c9a036e66a08b56b0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 10 Mar 2009 16:35:47 -0500 Subject: [PATCH 03/17] Move normalize-scanline-order implementation from images.bitmap to images Add upside-down? slot to image tuple Update cap for recent changes --- basis/images/bitmap/bitmap.factor | 6 +----- basis/images/images.factor | 15 ++++++++++----- basis/images/tiff/tiff.factor | 2 +- extra/cap/cap.factor | 27 ++++++++++++++------------- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/basis/images/bitmap/bitmap.factor b/basis/images/bitmap/bitmap.factor index 88eb984488..cf16df7d82 100755 --- a/basis/images/bitmap/bitmap.factor +++ b/basis/images/bitmap/bitmap.factor @@ -108,11 +108,6 @@ M: bitmap-image load-image* ( path bitmap -- bitmap ) load-bitmap-data process-bitmap-data fill-image-slots ; -M: bitmap-image normalize-scan-line-order - dup dim>> '[ - _ first 4 * reverse concat - ] change-bitmap ; - MACRO: (nbits>bitmap) ( bits -- ) [ -3 shift ] keep '[ bitmap-image new @@ -121,6 +116,7 @@ MACRO: (nbits>bitmap) ( bits -- ) swap >>width swap array-copy [ >>bitmap ] [ >>color-index ] bi _ >>bit-count fill-image-slots + t >>upside-down? ] ; : bgr>bitmap ( array height width -- bitmap ) diff --git a/basis/images/images.factor b/basis/images/images.factor index 82576774f4..cb44825e62 100644 --- a/basis/images/images.factor +++ b/basis/images/images.factor @@ -27,7 +27,7 @@ R16G16B16 R32G32B32 R16G16B16A16 R32G32B32A32 ; { R32G32B32A32 [ 16 ] } } case ; -TUPLE: image dim component-order bitmap ; +TUPLE: image dim component-order upside-down? bitmap ; : ( -- image ) image new ; inline @@ -82,11 +82,16 @@ M: ARGB normalize-component-order* M: ABGR normalize-component-order* drop ARGB>RGBA 4 BGR>RGB ; -GENERIC: normalize-scan-line-order ( image -- image ) - -M: image normalize-scan-line-order ; +: normalize-scan-line-order ( image -- image ) + dup upside-down?>> [ + dup dim>> first 4 * '[ + _ reverse concat + ] change-bitmap + f >>upside-down? + ] when ; : normalize-image ( image -- image ) [ >byte-array ] change-bitmap normalize-component-order - normalize-scan-line-order ; + normalize-scan-line-order + RGBA >>component-order ; diff --git a/basis/images/tiff/tiff.factor b/basis/images/tiff/tiff.factor index a50ac0cad9..2ea1b08e20 100755 --- a/basis/images/tiff/tiff.factor +++ b/basis/images/tiff/tiff.factor @@ -503,7 +503,7 @@ ERROR: unknown-component-order ifd ; : ifd>image ( ifd -- image ) { [ [ image-width find-tag ] [ image-length find-tag ] bi 2array ] - [ ifd-component-order ] + [ ifd-component-order f ] [ bitmap>> ] } cleave tiff-image boa ; diff --git a/extra/cap/cap.factor b/extra/cap/cap.factor index 1f62441028..64696759bb 100644 --- a/extra/cap/cap.factor +++ b/extra/cap/cap.factor @@ -1,30 +1,31 @@ ! Copyright (C) 2008 Doug Coleman, Joe Groff. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays byte-arrays kernel math namespaces -opengl.gl sequences math.vectors ui images.bitmap images.viewer +opengl.gl sequences math.vectors ui images images.viewer models ui.gadgets.worlds ui.gadgets fry alien.syntax ; IN: cap : screenshot-array ( world -- byte-array ) - dim>> [ first 3 * 4 align ] [ second ] bi * ; + dim>> [ first 4 * ] [ second ] bi * ; : gl-screenshot ( gadget -- byte-array ) [ - GL_BACK glReadBuffer - GL_PACK_ALIGNMENT 4 glPixelStorei - 0 0 - ] dip - [ dim>> first2 GL_BGR GL_UNSIGNED_BYTE ] + [ + GL_BACK glReadBuffer + GL_PACK_ALIGNMENT 4 glPixelStorei + 0 0 + ] dip + dim>> first2 GL_RGBA GL_UNSIGNED_BYTE + ] [ screenshot-array ] bi [ glReadPixels ] keep ; : screenshot ( window -- bitmap ) - [ gl-screenshot ] - [ dim>> first2 ] bi - bgr>bitmap ; - -: save-screenshot ( window path -- ) - [ screenshot ] dip save-bitmap ; + [ ] dip + [ gl-screenshot >>bitmap ] [ dim>> >>dim ] bi + RGBA >>component-order + t >>upside-down? + normalize-image ; : screenshot. ( window -- ) [ screenshot ] [ title>> ] bi open-window ; From 2f26d5f3dafff63264d052bf4c8ca873feac4a46 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 10 Mar 2009 16:58:35 -0500 Subject: [PATCH 04/17] images.viewer can now display some un-normalized images --- basis/opengl/textures/textures.factor | 6 ++++-- extra/images/viewer/viewer.factor | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/basis/opengl/textures/textures.factor b/basis/opengl/textures/textures.factor index 79af9be48b..48cdafb837 100644 --- a/basis/opengl/textures/textures.factor +++ b/basis/opengl/textures/textures.factor @@ -11,14 +11,16 @@ IN: opengl.textures TUPLE: texture loc dim texture-coords texture display-list disposed ; -format ( component-order -- format type ) +M: RGB component-order>format drop GL_RGB GL_UNSIGNED_BYTE ; +M: BGR component-order>format drop GL_BGR GL_UNSIGNED_BYTE ; M: RGBA component-order>format drop GL_RGBA GL_UNSIGNED_BYTE ; M: ARGB component-order>format drop GL_BGRA_EXT GL_UNSIGNED_INT_8_8_8_8_REV ; M: BGRA component-order>format drop GL_BGRA_EXT GL_UNSIGNED_BYTE ; +> first2 GL_RGBA GL_UNSIGNED_BYTE ] - [ bitmap>> ] bi glDrawPixels ; + [ dim>> first2 ] [ component-order>> component-order>format ] [ bitmap>> ] tri + glDrawPixels ; M: image-gadget draw-gadget* ( gadget -- ) image>> draw-image ; From ceafe8c69efe147123717f7329e29f50c0f2692a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 10 Mar 2009 16:59:15 -0500 Subject: [PATCH 05/17] Fix text rendering on top of transparent background --- basis/ui/pens/gradient/gradient.factor | 4 +++- basis/ui/pens/solid/solid.factor | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/basis/ui/pens/gradient/gradient.factor b/basis/ui/pens/gradient/gradient.factor index a137ae022b..485015b898 100644 --- a/basis/ui/pens/gradient/gradient.factor +++ b/basis/ui/pens/gradient/gradient.factor @@ -41,4 +41,6 @@ M: gradient draw-interior [ last-vertices>> gl-vertex-pointer ] [ last-colors>> gl-color-pointer ] [ colors>> draw-gradient ] - } cleave ; \ No newline at end of file + } cleave ; + +M: gradient pen-background 2drop transparent ; \ No newline at end of file diff --git a/basis/ui/pens/solid/solid.factor b/basis/ui/pens/solid/solid.factor index 32d400463e..950035e773 100644 --- a/basis/ui/pens/solid/solid.factor +++ b/basis/ui/pens/solid/solid.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel accessors opengl ui.pens ui.pens.caching ; +USING: kernel accessors opengl math colors ui.pens ui.pens.caching ; IN: ui.pens.solid TUPLE: solid < caching-pen color interior-vertices boundary-vertices ; @@ -29,4 +29,4 @@ M: solid draw-boundary (gl-rect) ; M: solid pen-background - nip color>> ; \ No newline at end of file + nip color>> dup alpha>> 1 number= [ drop transparent ] unless ; \ No newline at end of file From fb8ee9fb1192cd9c0f3d32666f7323787872d6f6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 10 Mar 2009 16:59:33 -0500 Subject: [PATCH 06/17] Clicking in slides window requests focus --- extra/slides/slides.factor | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extra/slides/slides.factor b/extra/slides/slides.factor index 6a5b7ab816..752d0b3ffa 100755 --- a/extra/slides/slides.factor +++ b/extra/slides/slides.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: arrays hashtables help.markup help.stylesheet io io.styles kernel math models namespaces sequences ui ui.gadgets -ui.gadgets.books ui.gadgets.panes ui.gestures ui.pens.gradient ui.render +ui.gadgets.books ui.gadgets.panes ui.gestures ui.pens.gradient parser accessors colors ; IN: slides @@ -98,6 +98,7 @@ TUPLE: slides < book ; parse-definition strip-tease [ parsed ] each ; parsing \ slides H{ + { T{ button-down } [ request-focus ] } { T{ key-down f f "DOWN" } [ next-page ] } { T{ key-down f f "UP" } [ prev-page ] } } set-gestures From 3acd00b4038b0a8939ca037d68bb7cb22e455023 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 10 Mar 2009 16:59:48 -0500 Subject: [PATCH 07/17] Fix tetris rendering --- extra/tetris/gl/gl.factor | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/extra/tetris/gl/gl.factor b/extra/tetris/gl/gl.factor index 70300779b5..f8c901ff56 100644 --- a/extra/tetris/gl/gl.factor +++ b/extra/tetris/gl/gl.factor @@ -35,7 +35,7 @@ IN: tetris.gl : scale-board ( width height board -- ) [ width>> ] [ height>> ] bi swapd [ / ] dup 2bi* 1 glScalef ; -: (draw-tetris) ( width height tetris -- ) +: draw-tetris ( width height tetris -- ) #! width and height are in pixels GL_MODELVIEW [ { @@ -44,7 +44,4 @@ IN: tetris.gl [ next-piece draw-next-piece ] [ current-piece draw-piece ] } cleave - ] do-matrix ; - -: draw-tetris ( width height tetris -- ) - origin get [ (draw-tetris) ] with-translation ; + ] do-matrix ; \ No newline at end of file From 712711e86940497fe7793a5c39fcc12e2909b814 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 10 Mar 2009 17:00:46 -0500 Subject: [PATCH 08/17] Replace png-gadget in otug-talk with icon gadget usage; convert PNG images to TIFF --- extra/otug-talk/2bi.png | Bin 6719 -> 0 bytes extra/otug-talk/2bi.tiff | Bin 0 -> 11744 bytes extra/otug-talk/2bi_at.png | Bin 7674 -> 0 bytes extra/otug-talk/2bi_at.tiff | Bin 0 -> 13728 bytes extra/otug-talk/2bi_star.png | Bin 6404 -> 0 bytes extra/otug-talk/2bi_star.tiff | Bin 0 -> 13924 bytes extra/otug-talk/bi.png | Bin 4837 -> 0 bytes extra/otug-talk/bi.tiff | Bin 0 -> 8872 bytes extra/otug-talk/bi_at.png | Bin 4660 -> 0 bytes extra/otug-talk/bi_at.tiff | Bin 0 -> 8848 bytes extra/otug-talk/bi_star.png | Bin 4415 -> 0 bytes extra/otug-talk/bi_star.tiff | Bin 0 -> 9784 bytes extra/otug-talk/otug-talk.factor | 53 ++++++++----------------------- 13 files changed, 13 insertions(+), 40 deletions(-) delete mode 100644 extra/otug-talk/2bi.png create mode 100644 extra/otug-talk/2bi.tiff delete mode 100644 extra/otug-talk/2bi_at.png create mode 100644 extra/otug-talk/2bi_at.tiff delete mode 100644 extra/otug-talk/2bi_star.png create mode 100644 extra/otug-talk/2bi_star.tiff delete mode 100644 extra/otug-talk/bi.png create mode 100644 extra/otug-talk/bi.tiff delete mode 100644 extra/otug-talk/bi_at.png create mode 100644 extra/otug-talk/bi_at.tiff delete mode 100644 extra/otug-talk/bi_star.png create mode 100644 extra/otug-talk/bi_star.tiff diff --git a/extra/otug-talk/2bi.png b/extra/otug-talk/2bi.png deleted file mode 100644 index 8f431f87ce059830ead37b1baeb701db3c5f7345..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6719 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 j1Ao29%Ks#yxh8WZ&-={xdFR}^ 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 literal 0 HcmV?d00001 diff --git a/extra/otug-talk/2bi_at.png b/extra/otug-talk/2bi_at.png deleted file mode 100644 index 55d42c2a4cf5afdcb45608740913e6a12b207fa6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7674 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 diff --git a/extra/otug-talk/2bi_at.tiff b/extra/otug-talk/2bi_at.tiff new file mode 100644 index 0000000000000000000000000000000000000000..e41ab98eeb4132fd3cb2e0ae7fa6ead6263294be GIT binary patch literal 13728 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 In-m592kY>u{Qv*} literal 0 HcmV?d00001 diff --git a/extra/otug-talk/2bi_star.png b/extra/otug-talk/2bi_star.png deleted file mode 100644 index 0fff37624b4c9f7d0292c23ce2735c2c934df35d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6404 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 Ml(m(r6yAmZ7tM)ScK`qY diff --git a/extra/otug-talk/2bi_star.tiff b/extra/otug-talk/2bi_star.tiff new file mode 100644 index 0000000000000000000000000000000000000000..f457ce5481a0d86c2db8816b03f7bbc9c1c08476 GIT binary patch literal 13924 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 XZK9=>kdUAmzM%;>SW|OfY$*6YG-qSv literal 0 HcmV?d00001 diff --git a/extra/otug-talk/bi_at.png b/extra/otug-talk/bi_at.png deleted file mode 100644 index 282f2f118d3bd5af5c471a3c848c0fb657ea8c6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4660 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 diff --git a/extra/otug-talk/bi_at.tiff b/extra/otug-talk/bi_at.tiff new file mode 100644 index 0000000000000000000000000000000000000000..07d25bcd01e25edf0e99f12968a6b9c2493f38e7 GIT binary patch literal 8848 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 ZVj}cZRpa8~R04NqLITZH36Jsz{{=X_sWJcn literal 0 HcmV?d00001 diff --git a/extra/otug-talk/bi_star.png b/extra/otug-talk/bi_star.png deleted file mode 100644 index e94e3710cfc5163b08e3b6b5f69a4c4e7ccbb922..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4415 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 diff --git a/extra/otug-talk/bi_star.tiff b/extra/otug-talk/bi_star.tiff new file mode 100644 index 0000000000000000000000000000000000000000..17f3350b51b562129d4c90142c31986fce640959 GIT binary patch literal 9784 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 literal 0 HcmV?d00001 diff --git a/extra/otug-talk/otug-talk.factor b/extra/otug-talk/otug-talk.factor index 16ee2b740b..2ce307ce20 100644 --- a/extra/otug-talk/otug-talk.factor +++ b/extra/otug-talk/otug-talk.factor @@ -1,41 +1,14 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: slides help.markup math arrays hashtables namespaces -sequences kernel sequences parser memoize io.encodings.binary -locals kernel.private tools.vocabs.browser assocs quotations - tools.vocabs tools.annotations tools.crossref -help.topics math.functions compiler.tree.optimizer -compiler.cfg.optimizer fry -ui.gadgets.panes tetris tetris.game combinators generalizations -multiline sequences.private ; +USING: slides help.markup math arrays hashtables namespaces sequences +kernel sequences parser memoize io.encodings.binary locals +kernel.private tools.vocabs.browser assocs quotations tools.vocabs +tools.annotations tools.crossref help.topics math.functions +compiler.tree.optimizer compiler.cfg.optimizer fry ui.gadgets.panes +tetris tetris.game combinators generalizations multiline +sequences.private ; IN: otug-talk -USING: cairo cairo.ffi cairo.gadgets accessors -io.backend ui.gadgets ; - -TUPLE: png-gadget < cairo-gadget surface ; - -: ( file -- gadget ) - png-gadget new-gadget - swap normalize-path - cairo_image_surface_create_from_png >>surface ; inline - -M: png-gadget pref-dim* ( gadget -- ) - surface>> - [ cairo_image_surface_get_width ] - [ cairo_image_surface_get_height ] - bi 2array ; - -M: png-gadget render-cairo* ( gadget -- ) - cr swap surface>> 0 0 cairo_set_source_surface - cr cairo_paint ; - -M: png-gadget ungraft* ( gadget -- ) - surface>> cairo_surface_destroy ; - -: $bitmap ( element -- ) - [ first gadget. ] ($block) ; - : $tetris ( element -- ) drop [ gadget. ] ($block) ; @@ -105,11 +78,11 @@ CONSTANT: otug-slides } { $slide "Data flow combinators - cleave family" { { $link bi } ", " { $link tri } ", " { $link cleave } } - { $bitmap "resource:extra/otug-talk/bi.png" } + { $image "resource:extra/otug-talk/bi.tiff" } } { $slide "Data flow combinators - cleave family" { { $link 2bi } ", " { $link 2tri } ", " { $link 2cleave } } - { $bitmap "resource:extra/otug-talk/2bi.png" } + { $image "resource:extra/otug-talk/2bi.tiff" } } { $slide "Data flow combinators" "First, let's define a data type:" @@ -128,19 +101,19 @@ CONSTANT: otug-slides } { $slide "Data flow combinators - spread family" { { $link bi* } ", " { $link tri* } ", " { $link spread } } - { $bitmap "resource:extra/otug-talk/bi_star.png" } + { $image "resource:extra/otug-talk/bi_star.tiff" } } { $slide "Data flow combinators - spread family" { { $link 2bi* } } - { $bitmap "resource:extra/otug-talk/2bi_star.png" } + { $image "resource:extra/otug-talk/2bi_star.tiff" } } { $slide "Data flow combinators - apply family" { { $link bi@ } ", " { $link tri@ } ", " { $link napply } } - { $bitmap "resource:extra/otug-talk/bi_at.png" } + { $image "resource:extra/otug-talk/bi_at.tiff" } } { $slide "Data flow combinators - apply family" { { $link 2bi@ } } - { $bitmap "resource:extra/otug-talk/2bi_at.png" } + { $image "resource:extra/otug-talk/2bi_at.tiff" } } { $slide "Shuffle words" "When data flow combinators are not enough" From b3f09a9aed8a29602046e4180943639c5f017530 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 10 Mar 2009 17:28:17 -0500 Subject: [PATCH 09/17] Check for words which are not classes but have a $class-description element anyway --- basis/help/lint/lint.factor | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/basis/help/lint/lint.factor b/basis/help/lint/lint.factor index 57f64459c8..2281c295c3 100755 --- a/basis/help/lint/lint.factor +++ b/basis/help/lint/lint.factor @@ -132,6 +132,11 @@ SYMBOL: vocabs-quot [ check-descriptions ] } cleave ; +: check-class-description ( word element -- ) + [ class? not ] + [ { $class-description } swap elements empty? not ] bi* and + [ "A word that is not a class has a $class-description" throw ] when ; + : all-word-help ( words -- seq ) [ word-help ] filter ; @@ -153,7 +158,8 @@ M: help-error error. dup '[ _ dup word-help [ check-values ] - [ nip [ check-nulls ] [ check-see-also ] [ check-markup ] tri ] 2bi + [ check-class-description ] + [ nip [ check-nulls ] [ check-see-also ] [ check-markup ] tri ] 2tri ] check-something ] [ drop ] if ; From 16ddc461b4c2dbb528a785dc0a5dc19cf3db5f0b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 10 Mar 2009 17:28:34 -0500 Subject: [PATCH 10/17] Document ui.gadgets.glass and fix help lint failures in UI docs --- basis/ui/gadgets/glass/glass-docs.factor | 55 +++++++++++++++++++ basis/ui/gadgets/glass/glass.factor | 2 +- basis/ui/gadgets/menus/menus-docs.factor | 2 +- .../gadgets/status-bar/status-bar-docs.factor | 2 +- basis/ui/ui-docs.factor | 1 + 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 basis/ui/gadgets/glass/glass-docs.factor diff --git a/basis/ui/gadgets/glass/glass-docs.factor b/basis/ui/gadgets/glass/glass-docs.factor new file mode 100644 index 0000000000..bd9028d414 --- /dev/null +++ b/basis/ui/gadgets/glass/glass-docs.factor @@ -0,0 +1,55 @@ +IN: ui.gadgets.glass +USING: help.markup help.syntax ui.gadgets math.rectangles ; + +HELP: show-glass +{ $values { "owner" gadget } { "child" gadget } { "visible-rect" rect } } +{ $description "Displays " { $snippet "child" } " in the glass layer of the window containing " { $snippet "owner" } "." + $nl + "The child's position is calculated with a heuristic:" + { $list + "The child must fit inside the window" + { "The child must not obscure " { $snippet "visible-rect" } ", which is a rectangle whose origin is relative to " { $snippet "owner" } } + { "The child must otherwise be as close as possible to the edges of " { $snippet "visible-rect" } } + } + "For example, when displaying a menu, " { $snippet "visible-rect" } " is a single point at the mouse location, and when displaying a completion popup, " { $snippet "visible-rect" } " contains the bounds of the text element being completed." +} ; + +HELP: hide-glass +{ $values { "child" gadget } } +{ $description "Hides a gadget displayed in a glass layer." } ; + +HELP: hide-glass-hook +{ $values { "gadget" gadget } } +{ $description "Called when a gadget displayed in a glass layer is hidden. The gadget can perform cleanup tasks here." } ; + +HELP: pass-to-popup +{ $values { "gesture" "a gesture" } { "owner" "the popup's owner" } { "?" "a boolean" } } +{ $description "Resends the gesture to the popup displayed by " { $snippet "owner" } ". The owner must have a " { $slot "popup" } " slot. Outputs " { $link f } " if the gesture was handled, " { $link t } " otherwise." } ; + +HELP: show-popup +{ $values { "owner" gadget } { "popup" gadget } { "visible-rect" rect } } +{ $description "Displays " { $snippet "popup" } " in the glass layer of the window containing " { $snippet "owner" } " as a popup." + $nl + "This word differs from " { $link show-glass } " in two respects:" + { $list + { "The popup is stored in the owner's " { $slot "popup" } " slot; the owner can call " { $link pass-to-popup } " to pass keyboard gestures to the popup" } + { "Pressing " { $snippet "ESC" } " with the popup visible will hide it" } + } +} ; + +ARTICLE: "ui.gadgets.glass" "Glass layers" +"The " { $vocab-link "ui.gadgets.glass" } " vocabulary implements support for displaying gadgets in the glass layer of a window. The gadget can be positioned arbitrarily within the glass layer, and while it is visible, mouse clicks outside of the glass layer are intercepted to hide the glass layer. Multiple glass layers can be active at a time; they behave as if stacked on top of each other." +$nl +"This feature is used for completion popups and " { $link "ui.gadgets.menus" } " in the " { $link "ui-tools" } "." +$nl +"Displaying a gadget in a glass layer:" +{ $subsection show-glass } +"Hiding a gadget in a glass layer:" +{ $subsection hide-glass } +"Callback generic invoked on the gadget when its glass layer is hidden:" +{ $subsection hide-glass-hook } +"Popup gadgets add support for forwarding keyboard gestures from an owner gadget to the glass layer:" +{ $subsection show-popup } +{ $subsection pass-to-popup } ; + +ABOUT: "ui.gadgets.glass" \ No newline at end of file diff --git a/basis/ui/gadgets/glass/glass.factor b/basis/ui/gadgets/glass/glass.factor index a8f438c85e..af169235b4 100644 --- a/basis/ui/gadgets/glass/glass.factor +++ b/basis/ui/gadgets/glass/glass.factor @@ -71,7 +71,7 @@ popup H{ { T{ key-down f f "ESC" } [ hide-glass ] } } set-gestures -: pass-to-popup ( gesture interactor -- ? ) +: pass-to-popup ( gesture owner -- ? ) popup>> focusable-child resend-gesture ; : show-popup ( owner popup visible-rect -- ) diff --git a/basis/ui/gadgets/menus/menus-docs.factor b/basis/ui/gadgets/menus/menus-docs.factor index d7297217ed..ad0881a382 100644 --- a/basis/ui/gadgets/menus/menus-docs.factor +++ b/basis/ui/gadgets/menus/menus-docs.factor @@ -16,7 +16,7 @@ HELP: show-commands-menu { $notes "Useful for right-click context menus." } ; ARTICLE: "ui.gadgets.menus" "Popup menus" -"The " { $vocab-link "ui.gadgets.menus" } " vocabulary implements popup menus." +"The " { $vocab-link "ui.gadgets.menus" } " vocabulary displays popup menus in " { $link "ui.gadgets.glass" } "." { $subsection } { $subsection show-menu } { $subsection show-commands-menu } ; diff --git a/basis/ui/gadgets/status-bar/status-bar-docs.factor b/basis/ui/gadgets/status-bar/status-bar-docs.factor index f5a6409fca..57c69c2a66 100644 --- a/basis/ui/gadgets/status-bar/status-bar-docs.factor +++ b/basis/ui/gadgets/status-bar/status-bar-docs.factor @@ -3,7 +3,7 @@ ui.gadgets ui.gadgets.worlds ui ; IN: ui.gadgets.status-bar HELP: show-status -{ $values { "string" string } { "gadget" gadget } } +{ $values { "string/f" string } { "gadget" gadget } } { $description "Displays a status message in the gadget's world." } { $notes "The status message will only be visible if the window was opened with " { $link open-status-window } ", and not " { $link open-window } "." } ; diff --git a/basis/ui/ui-docs.factor b/basis/ui/ui-docs.factor index d08dea299e..f2b6154745 100644 --- a/basis/ui/ui-docs.factor +++ b/basis/ui/ui-docs.factor @@ -171,6 +171,7 @@ ARTICLE: "ui-layouts" "Gadget hierarchy and layouts" { $subsection "ui-frame-layout" } { $subsection "ui-book-layout" } "Advanced topics:" +{ $subsection "ui.gadgets.glass" } { $subsection "ui-null-layout" } { $subsection "ui-incremental-layout" } { $subsection "ui-layout-impl" } From 638cef282457db0780107efdc272ba1cb0653493 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Tue, 10 Mar 2009 18:27:04 -0500 Subject: [PATCH 11/17] Many regexp changes, improving speed and organization --- .../combinators/combinators-tests.factor | 2 +- basis/regexp/compiler/compiler.factor | 43 ++--- basis/regexp/negation/negation.factor | 6 +- basis/regexp/regexp-docs.factor | 2 +- basis/regexp/regexp-tests.factor | 24 ++- basis/regexp/regexp.factor | 182 +++++++++++++----- 6 files changed, 175 insertions(+), 84 deletions(-) diff --git a/basis/regexp/combinators/combinators-tests.factor b/basis/regexp/combinators/combinators-tests.factor index 6690440345..ddfd0dcaad 100644 --- a/basis/regexp/combinators/combinators-tests.factor +++ b/basis/regexp/combinators/combinators-tests.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2009 Daniel Ehrenberg ! See http://factorcode.org/license.txt for BSD license. -USING: regexp.combinators tools.test regexp kernel sequences regexp.matchers ; +USING: regexp.combinators tools.test regexp kernel sequences ; IN: regexp.combinators.tests : strings ( -- regexp ) diff --git a/basis/regexp/compiler/compiler.factor b/basis/regexp/compiler/compiler.factor index eedf05a81e..0e0c0eaae6 100644 --- a/basis/regexp/compiler/compiler.factor +++ b/basis/regexp/compiler/compiler.factor @@ -1,19 +1,19 @@ ! Copyright (C) 2009 Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: regexp.classes kernel sequences regexp.negation -quotations regexp.minimize assocs fry math locals combinators +quotations assocs fry math locals combinators accessors words compiler.units kernel.private strings -sequences.private arrays regexp.matchers call namespaces +sequences.private arrays call namespaces regexp.transition-tables combinators.short-circuit ; IN: regexp.compiler GENERIC: question>quot ( question -- quot ) -quot drop [ 2drop t ] ; M: beginning-of-input question>quot @@ -122,34 +122,23 @@ C: box [ values ] bi swap ; -: dfa>word ( dfa -- word ) +: dfa>main-word ( dfa -- word ) states>words [ states>code ] keep start-state>> ; -: check-string ( string -- string ) - ! Make this configurable - dup string? [ "String required" throw ] unless ; - -: setup-regexp ( start-index string -- f start-index string ) - [ f ] [ >fixnum ] [ check-string ] tri* ; inline - PRIVATE> -! The quotation returned is ( start-index string -- i/f ) +: simple-define-temp ( quot effect -- word ) + [ [ define-temp ] with-compilation-unit ] call( quot effect -- word ) ; -: dfa>quotation ( dfa -- quot ) - dfa>word execution-quot '[ setup-regexp @ ] ; +: dfa>word ( dfa -- quot ) + dfa>main-word execution-quot '[ drop [ f ] 2dip @ ] + (( start-index string regexp -- i/f )) simple-define-temp ; -: dfa>shortest-quotation ( dfa -- quot ) - t shortest? [ dfa>quotation ] with-variable ; +: dfa>shortest-word ( dfa -- word ) + t shortest? [ dfa>word ] with-variable ; -: dfa>reverse-quotation ( dfa -- quot ) - t backwards? [ dfa>quotation ] with-variable ; +: dfa>reverse-word ( dfa -- word ) + t backwards? [ dfa>word ] with-variable ; -: dfa>reverse-shortest-quotation ( dfa -- quot ) - t backwards? [ dfa>shortest-quotation ] with-variable ; - -TUPLE: quot-matcher quot ; -C: quot-matcher - -M: quot-matcher match-index-from - quot>> call( index string -- i/f ) ; +: dfa>reverse-shortest-word ( dfa -- word ) + t backwards? [ dfa>shortest-word ] with-variable ; diff --git a/basis/regexp/negation/negation.factor b/basis/regexp/negation/negation.factor index 0633dca192..8b0a2f6edf 100644 --- a/basis/regexp/negation/negation.factor +++ b/basis/regexp/negation/negation.factor @@ -6,9 +6,6 @@ regexp.ast regexp.transition-tables regexp.minimize regexp.dfa namespaces ; IN: regexp.negation -: ast>dfa ( parse-tree -- minimal-dfa ) - construct-nfa disambiguate construct-dfa minimize ; - CONSTANT: fail-state -1 : add-default-transition ( state's-transitions -- new-state's-transitions ) @@ -49,5 +46,8 @@ CONSTANT: fail-state -1 [ final-states>> keys first ] [ nfa-table get [ transitions>> ] bi@ swap update ] tri ; +: ast>dfa ( parse-tree -- minimal-dfa ) + construct-nfa disambiguate construct-dfa minimize ; + M: negation nfa-node ( node -- start end ) term>> ast>dfa negate-table adjoin-dfa ; diff --git a/basis/regexp/regexp-docs.factor b/basis/regexp/regexp-docs.factor index d77abe877e..ce4a54df87 100644 --- a/basis/regexp/regexp-docs.factor +++ b/basis/regexp/regexp-docs.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008, 2009 Doug Coleman, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel strings help.markup help.syntax regexp.matchers math ; +USING: kernel strings help.markup help.syntax math ; IN: regexp ABOUT: "regexp" diff --git a/basis/regexp/regexp-tests.factor b/basis/regexp/regexp-tests.factor index 99cb8dbd22..fa907011fd 100644 --- a/basis/regexp/regexp-tests.factor +++ b/basis/regexp/regexp-tests.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008, 2009 Doug Coleman, Daniel Ehrenberg ! See http://factorcode.org/license.txt for BSD license. USING: regexp tools.test kernel sequences regexp.parser regexp.private -eval strings multiline accessors regexp.matchers ; +eval strings multiline accessors ; IN: regexp-tests \ must-infer @@ -239,11 +239,11 @@ IN: regexp-tests [ f ] [ "A" "\\p{Lower}" matches? ] unit-test [ t ] [ "A" R/ \p{Lower}/i matches? ] unit-test -[ t ] [ "abc" reverse R/ abc/r matches? ] unit-test -[ t ] [ "abc" reverse R/ a[bB][cC]/r matches? ] unit-test +[ t ] [ "abc" R/ abc/r matches? ] unit-test +[ t ] [ "abc" R/ a[bB][cC]/r matches? ] unit-test -[ t ] [ 3 "xabc" R/ abc/ match-index-from >boolean ] unit-test -[ t ] [ 3 "xabc" R/ a[bB][cC]/ match-index-from >boolean ] unit-test +[ t ] [ 3 "xabc" R/ abc/r match-index-from >boolean ] unit-test +[ t ] [ 3 "xabc" R/ a[bB][cC]/r match-index-from >boolean ] unit-test [ t ] [ "s@f" "[a-z.-]@[a-z]" matches? ] unit-test [ f ] [ "a" "[a-z.-]@[a-z]" matches? ] unit-test @@ -341,9 +341,19 @@ IN: regexp-tests [ t ] [ "aaaa" R/ .*a./ matches? ] unit-test +[ f ] [ "ab" R/ (?~ac|\p{Lower}b)/ matches? ] unit-test +[ f ] [ "ab" R/ (?~ac|[a-z]b)/ matches? ] unit-test +[ f ] [ "ac" R/ (?~ac|\p{Lower}b)/ matches? ] unit-test +[ f ] [ "ac" R/ (?~ac|[a-z]b)/ matches? ] unit-test +[ f ] [ "ac" R/ (?~[a-zA-Z]c|\p{Lower}b)/ matches? ] unit-test +[ f ] [ "ab" R/ (?~[a-zA-Z]c|\p{Lower}b)/ matches? ] unit-test +[ f ] [ "πb" R/ (?~[a-zA-Z]c|\p{Lower}b)/ matches? ] unit-test +[ t ] [ "πc" R/ (?~[a-zA-Z]c|\p{Lower}b)/ matches? ] unit-test +[ t ] [ "Ab" R/ (?~[a-zA-Z]c|\p{Lower}b)/ matches? ] unit-test + ! DFA is compiled when needed, or when literal -[ f ] [ "foo" dfa>> >boolean ] unit-test -[ t ] [ R/ foo/ dfa>> >boolean ] unit-test +[ regexp-initial-word ] [ "foo" dfa>> ] unit-test +[ f ] [ R/ foo/ dfa>> \ regexp-initial-word = ] unit-test [ t ] [ "a" R/ ^a/ matches? ] unit-test [ f ] [ "\na" R/ ^a/ matches? ] unit-test diff --git a/basis/regexp/regexp.factor b/basis/regexp/regexp.factor index f938ddf60a..aacd888ccb 100644 --- a/basis/regexp/regexp.factor +++ b/basis/regexp/regexp.factor @@ -2,71 +2,162 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators kernel math sequences strings sets assocs prettyprint.backend prettyprint.custom make lexer -namespaces parser arrays fry locals regexp.minimize -regexp.parser regexp.nfa regexp.dfa regexp.classes -regexp.transition-tables splitting sorting regexp.ast -regexp.negation regexp.matchers regexp.compiler ; +namespaces parser arrays fry locals regexp.parser splitting +sorting regexp.ast regexp.negation regexp.compiler words +call call.private math.ranges ; IN: regexp TUPLE: regexp { raw read-only } { parse-tree read-only } { options read-only } - dfa reverse-dfa ; + dfa next-match ; -: make-regexp ( string ast -- regexp ) - f f f f regexp boa ; foldable - ! Foldable because, when the dfa slot is set, - ! it'll be set to the same thing regardless of who sets it +TUPLE: reverse-regexp < regexp ; -: ( string options -- regexp ) - [ dup parse-regexp ] [ string>options ] bi* - f f regexp boa ; + ( string -- regexp ) "" ; +: maybe-negated ( lookaround quot -- regexp-quot ) + '[ term>> @ ] [ positive?>> [ ] [ not ] ? ] bi compose ; inline -TUPLE: reverse-matcher regexp ; -C: reverse-matcher -! Reverse matchers won't work properly with most combinators, for now +M: lookahead question>quot ! Returns ( index string -- ? ) + [ ast>dfa dfa>shortest-word '[ f _ execute ] ] maybe-negated ; + +: ( ast -- reversed ) + "r" string>options ; + +M: lookbehind question>quot ! Returns ( index string -- ? ) + [ + + ast>dfa dfa>reverse-shortest-word + '[ [ 1- ] dip f _ execute ] + ] maybe-negated ; + +> execute( index string regexp -- i/f ) ; + +: match-index-head ( string regexp -- index/f ) + [ 0 ] 2dip [ check-string ] dip match-index-from ; + +PRIVATE> + +: matches? ( string regexp -- ? ) + dupd match-index-head + [ swap length = ] [ drop f ] if* ; + + ] [ 2drop f ] if* ; inline + +: match-from ( i string quot -- slice/f ) + [ [ length [a,b) ] keep ] dip + '[ _ _ match-slice ] map-find drop ; inline + +: next-match ( i string quot -- i match/f ) + match-from [ dup [ to>> ] when ] keep ; inline + +: do-next-match ( i string regexp -- i match/f ) + dup next-match>> execute( i string regexp -- i match/f ) ; + +PRIVATE> + +: all-matches ( string regexp -- seq ) + [ check-string ] dip + [ 0 [ dup ] ] 2dip '[ _ _ do-next-match ] produce + nip but-last ; + +: count-matches ( string regexp -- n ) + all-matches length ; + +> ] map 0 prefix + slices [ from>> ] map string length suffix + [ string ] 2map ; + +: match-head ( str regexp -- slice/f ) + [ + [ 0 ] [ check-string ] [ dup dfa>> '[ _ _ execute ] ] tri* + match-from + ] call( str regexp -- slice/f ) ; + +PRIVATE> + +: re-split1 ( string regexp -- before after/f ) + dupd match-head [ 1array split-slices first2 ] [ f ] if* ; + +: re-split ( string regexp -- seq ) + dupd all-matches split-slices ; + +: re-replace ( string regexp replacement -- result ) + [ re-split ] dip join ; > ] [ options>> ] bi ; -: compile-regexp ( regexp -- regexp ) - dup '[ [ _ get-ast ast>dfa dfa>quotation ] unless* ] change-dfa ; +GENERIC: compile-regexp ( regex -- regexp ) -: ( ast -- reversed ) - "r" string>options ; +: regexp-initial-word ( i string regexp -- i/f ) + compile-regexp match-index-from ; -: maybe-negated ( lookaround quot -- regexp-quot ) - '[ term>> @ ] [ positive?>> [ ] [ not ] ? ] bi compose ; inline - -M: lookahead question>quot ! Returns ( index string -- ? ) - [ ast>dfa dfa>shortest-quotation ] maybe-negated ; - -M: lookbehind question>quot ! Returns ( index string -- ? ) - [ - - ast>dfa dfa>reverse-shortest-quotation - [ [ 1- ] dip ] prepose - ] maybe-negated ; - -: compile-reverse ( regexp -- regexp ) +: do-compile-regexp ( regexp -- regexp ) dup '[ - [ - _ get-ast - ast>dfa dfa>reverse-quotation - ] unless* - ] change-reverse-dfa ; + dup \ regexp-initial-word = + [ drop _ get-ast ast>dfa dfa>word ] when + ] change-dfa ; -M: regexp match-index-from - compile-regexp dfa>> match-index-from ; +M: regexp compile-regexp ( regexp -- regexp ) + do-compile-regexp ; -M: reverse-matcher match-index-from - regexp>> compile-reverse reverse-dfa>> - match-index-from ; +M: reverse-regexp compile-regexp ( regexp -- regexp ) + t backwards? [ do-compile-regexp ] with-variable ; + +GENERIC: compile-next-match ( regexp -- regexp ) + +: next-initial-word ( i string regexp -- i slice/f ) + compile-next-match do-next-match ; + +M: regexp compile-next-match ( regexp -- regexp ) + dup '[ + dup \ next-initial-word = [ + drop _ compile-regexp dfa>> + '[ _ '[ _ _ execute ] next-match ] + (( i string -- i match/f )) simple-define-temp + ] when + ] change-next-match ; + +! Write M: reverse-regexp compile-next-match + +PRIVATE> + +: new-regexp ( string ast options class -- regexp ) + [ \ regexp-initial-word \ next-initial-word ] dip boa ; inline + +: make-regexp ( string ast -- regexp ) + f f regexp new-regexp ; + +: ( string options -- regexp ) + [ dup parse-regexp ] [ string>options ] bi* + dup on>> reversed-regexp swap member? + [ reverse-regexp new-regexp ] + [ regexp new-regexp ] if ; + +: ( string -- regexp ) "" ; + + compile-regexp parsed ; + compile-next-match parsed ; PRIVATE> @@ -120,3 +211,4 @@ M: regexp pprint* [ options>> options>string % ] bi ] "" make ] keep present-text ; + From 987cd1c8ce78c9ae459f86b7dfce7a946a0971c0 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Tue, 10 Mar 2009 18:27:33 -0500 Subject: [PATCH 12/17] Moving regexp.matchers back to regexp --- basis/globs/globs.factor | 2 +- basis/validators/validators.factor | 2 +- basis/xmode/marker/marker.factor | 6 +++--- extra/benchmark/regex-dna/regex-dna.factor | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/basis/globs/globs.factor b/basis/globs/globs.factor index 173187574b..cac7fd9a2f 100644 --- a/basis/globs/globs.factor +++ b/basis/globs/globs.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2007, 2009 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. -USING: sequences kernel regexp.combinators regexp.matchers strings unicode.case +USING: sequences kernel regexp.combinators strings unicode.case peg.ebnf regexp arrays ; IN: globs diff --git a/basis/validators/validators.factor b/basis/validators/validators.factor index 740cf7db13..f0ee13dd38 100644 --- a/basis/validators/validators.factor +++ b/basis/validators/validators.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2006, 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. USING: kernel continuations sequences math namespaces make sets -math.parser math.ranges assocs regexp regexp.matchers unicode.categories arrays +math.parser math.ranges assocs regexp unicode.categories arrays hashtables words classes quotations xmode.catalog unicode.case ; IN: validators diff --git a/basis/xmode/marker/marker.factor b/basis/xmode/marker/marker.factor index de1f4254ea..d3ad266b5d 100755 --- a/basis/xmode/marker/marker.factor +++ b/basis/xmode/marker/marker.factor @@ -1,11 +1,11 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -IN: xmode.marker USING: kernel namespaces make xmode.rules xmode.tokens xmode.marker.state xmode.marker.context xmode.utilities xmode.catalog sequences math assocs combinators strings -regexp splitting ascii unicode.case regexp.matchers -ascii combinators.short-circuit accessors ; +regexp splitting unicode.case +combinators.short-circuit accessors ; +IN: xmode.marker ! Next two words copied from parser-combinators ! Just like head?, but they optionally ignore case diff --git a/extra/benchmark/regex-dna/regex-dna.factor b/extra/benchmark/regex-dna/regex-dna.factor index 29cb0b7357..5c11be357f 100644 --- a/extra/benchmark/regex-dna/regex-dna.factor +++ b/extra/benchmark/regex-dna/regex-dna.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors regexp.matchers prettyprint io io.encodings.ascii +USING: accessors prettyprint io io.encodings.ascii io.files kernel sequences assocs namespaces regexp ; IN: benchmark.regex-dna From 8836b2a73b9513472a0a43bf68130744755781b2 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Tue, 10 Mar 2009 19:17:25 -0500 Subject: [PATCH 13/17] matches? works as expected for reversed regexps --- basis/regexp/regexp-tests.factor | 12 ++++++------ basis/regexp/regexp.factor | 11 +++++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/basis/regexp/regexp-tests.factor b/basis/regexp/regexp-tests.factor index fa907011fd..f7d3dae3f3 100644 --- a/basis/regexp/regexp-tests.factor +++ b/basis/regexp/regexp-tests.factor @@ -211,8 +211,8 @@ IN: regexp-tests [ f ] [ "aaaxb" "a+ab" matches? ] unit-test [ t ] [ "aaacb" "a+cb" matches? ] unit-test -[ 3 ] [ "aaacb" "a*" match-index-head ] unit-test -[ 2 ] [ "aaacb" "aa?" match-index-head ] unit-test +[ "aaa" ] [ "aaacb" "a*" match-head >string ] unit-test +[ "aa" ] [ "aaacb" "aa?" match-head >string ] unit-test [ t ] [ "aaa" R/ AAA/i matches? ] unit-test [ f ] [ "aax" R/ AAA/i matches? ] unit-test @@ -310,8 +310,8 @@ IN: regexp-tests [ "a" ] [ "ba" "(?<=b)(?<=b)a" match-head >string ] unit-test [ "a" ] [ "cab" "(?<=c)a(?=b)" match-head >string ] unit-test -[ 3 ] [ "foobar" "foo(?=bar)" match-index-head ] unit-test -[ f ] [ "foobxr" "foo(?=bar)" match-index-head ] unit-test +[ 3 ] [ "foobar" "foo(?=bar)" match-head length ] unit-test +[ f ] [ "foobxr" "foo(?=bar)" match-head ] unit-test ! Bug in parsing word [ t ] [ "a" R' a' matches? ] unit-test @@ -424,8 +424,8 @@ IN: regexp-tests [ 1 ] [ "a\r" R/ a$/m count-matches ] unit-test [ 1 ] [ "a\r\n" R/ a$/m count-matches ] unit-test -[ f ] [ "foobxr" "foo\\z" match-index-head ] unit-test -[ 3 ] [ "foo" "foo\\z" match-index-head ] unit-test +[ f ] [ "foobxr" "foo\\z" match-head ] unit-test +[ 3 ] [ "foo" "foo\\z" match-head length ] unit-test ! [ t ] [ "foo" "\\bfoo\\b" matches? ] unit-test ! [ t ] [ "afoob" "\\Bfoo\\B" matches? ] unit-test diff --git a/basis/regexp/regexp.factor b/basis/regexp/regexp.factor index aacd888ccb..94bbc2af58 100644 --- a/basis/regexp/regexp.factor +++ b/basis/regexp/regexp.factor @@ -44,14 +44,17 @@ M: lookbehind question>quot ! Returns ( index string -- ? ) ! and that string is a string. dup dfa>> execute( index string regexp -- i/f ) ; -: match-index-head ( string regexp -- index/f ) - [ 0 ] 2dip [ check-string ] dip match-index-from ; +GENERIC: end/start ( string regexp -- end start ) +M: regexp end/start drop length 0 ; +M: reverse-regexp end/start drop length 1- -1 swap ; PRIVATE> : matches? ( string regexp -- ? ) - dupd match-index-head - [ swap length = ] [ drop f ] if* ; + [ end/start ] 2keep + [ check-string ] dip + match-index-from + [ swap = ] [ drop f ] if* ; Date: Tue, 10 Mar 2009 19:34:49 -0500 Subject: [PATCH 14/17] Fixing help-lint for regexp; adding first-match and re-contains? --- basis/regexp/regexp-docs.factor | 27 ++++++++++++++++-------- basis/regexp/regexp-tests.factor | 36 ++++++++++++++++++-------------- basis/regexp/regexp.factor | 15 ++++++------- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/basis/regexp/regexp-docs.factor b/basis/regexp/regexp-docs.factor index ce4a54df87..1d28e5e92f 100644 --- a/basis/regexp/regexp-docs.factor +++ b/basis/regexp/regexp-docs.factor @@ -39,13 +39,14 @@ ARTICLE: { "regexp" "theory" } "The theory of regular expressions" "The Factor regular expression engine was built with the design decision to support negation and intersection at the expense of backreferences. This lets us have a guaranteed linear-time matching algorithm. Systems like Ragel and Lex also use this algorithm, but in the Factor regular expression engine, all other features of regexps are still present." ; ARTICLE: { "regexp" "operations" } "Matching operations with regular expressions" -{ $subsection all-matches } { $subsection matches? } +{ $subsection re-contains? } +{ $subsection first-match } +{ $subsection all-matches } { $subsection re-split1 } { $subsection re-split } { $subsection re-replace } -{ $subsection count-matches } -{ $subsection re-replace } ; +{ $subsection count-matches } ; HELP: { $values { "string" string } { "regexp" regexp } } @@ -63,25 +64,33 @@ HELP: regexp { $class-description "The class of regular expressions. To construct these, see " { $link { "regexp" "construction" } } "." } ; HELP: matches? -{ $values { "string" string } { "matcher" regexp } { "?" "a boolean" } } +{ $values { "string" string } { "regexp" regexp } { "?" "a boolean" } } { $description "Tests if the string as a whole matches the given regular expression." } ; HELP: re-split1 -{ $values { "string" string } { "matcher" regexp } { "before" string } { "after/f" string } } +{ $values { "string" string } { "regexp" regexp } { "before" string } { "after/f" string } } { $description "Searches the string for a substring which matches the pattern. If found, the input string is split on the leftmost and longest occurence of the match, and the two halves are given as output. If no match is found, then the input string and " { $link f } " are output." } ; HELP: all-matches -{ $values { "string" string } { "matcher" regexp } { "seq" "a sequence of slices of the input" } } +{ $values { "string" string } { "regexp" regexp } { "seq" "a sequence of slices of the input" } } { $description "Finds a sequence of disjoint substrings which each match the pattern. It chooses this by finding the leftmost longest match, and then the leftmost longest match which starts after the end of the previous match, and so on." } ; HELP: count-matches -{ $values { "string" string } { "matcher" regexp } { "n" integer } } +{ $values { "string" string } { "regexp" regexp } { "n" integer } } { $description "Counts how many disjoint matches the regexp has in the string, as made unambiguous by " { $link all-matches } "." } ; HELP: re-split -{ $values { "string" string } { "matcher" regexp } { "seq" "a sequence of slices of the input" } } +{ $values { "string" string } { "regexp" regexp } { "seq" "a sequence of slices of the input" } } { $description "Splits the input string into chunks separated by the regular expression. Each chunk contains no match of the regexp. The chunks are chosen by the strategy of " { $link all-matches } "." } ; HELP: re-replace -{ $values { "string" string } { "matcher" regexp } { "replacement" string } { "result" string } } +{ $values { "string" string } { "regexp" regexp } { "replacement" string } { "result" string } } { $description "Replaces substrings which match the input regexp with the given replacement text. The boundaries of the substring are chosen by the strategy used by " { $link all-matches } "." } ; + +HELP: first-match +{ $values { "string" string } { "regexp" regexp } { "slice/f" "the match, if one exists" } } +{ $description "Finds the first match of the regular expression in the string, and returns it as a slice. If there is no match, then " { $link f } " is returned." } ; + +HELP: re-contains? +{ $values { "string" string } { "regexp" regexp } { "?" "a boolean" } } +{ $description "Determines whether the string has a substring which matches the regular expression given." } ; diff --git a/basis/regexp/regexp-tests.factor b/basis/regexp/regexp-tests.factor index f7d3dae3f3..f05416ab94 100644 --- a/basis/regexp/regexp-tests.factor +++ b/basis/regexp/regexp-tests.factor @@ -211,8 +211,8 @@ IN: regexp-tests [ f ] [ "aaaxb" "a+ab" matches? ] unit-test [ t ] [ "aaacb" "a+cb" matches? ] unit-test -[ "aaa" ] [ "aaacb" "a*" match-head >string ] unit-test -[ "aa" ] [ "aaacb" "aa?" match-head >string ] unit-test +[ "aaa" ] [ "aaacb" "a*" first-match >string ] unit-test +[ "aa" ] [ "aaacb" "aa?" first-match >string ] unit-test [ t ] [ "aaa" R/ AAA/i matches? ] unit-test [ f ] [ "aax" R/ AAA/i matches? ] unit-test @@ -268,13 +268,13 @@ IN: regexp-tests [ ] [ "USING: regexp kernel ; R' \\*[^\s*][^*]*\\*' drop" eval ] unit-test -[ "ab" ] [ "ab" "(a|ab)(bc)?" match-head >string ] unit-test -[ "abc" ] [ "abc" "(a|ab)(bc)?" match-head >string ] unit-test +[ "ab" ] [ "ab" "(a|ab)(bc)?" first-match >string ] unit-test +[ "abc" ] [ "abc" "(a|ab)(bc)?" first-match >string ] unit-test -[ "ab" ] [ "ab" "(ab|a)(bc)?" match-head >string ] unit-test -[ "abc" ] [ "abc" "(ab|a)(bc)?" match-head >string ] unit-test +[ "ab" ] [ "ab" "(ab|a)(bc)?" first-match >string ] unit-test +[ "abc" ] [ "abc" "(ab|a)(bc)?" first-match >string ] unit-test -[ "b" ] [ "aaaaaaaaaaaaaaaaaaaaaaab" "((a*)*b)*b" match-head >string ] unit-test +[ "b" ] [ "aaaaaaaaaaaaaaaaaaaaaaab" "((a*)*b)*b" first-match >string ] unit-test [ { "1" "2" "3" "4" } ] [ "1ABC2DEF3GHI4" R/ [A-Z]+/ re-split [ >string ] map ] unit-test @@ -300,18 +300,18 @@ IN: regexp-tests [ "-- title --" ] [ "== title ==" R/ =/ "-" re-replace ] unit-test -[ "" ] [ "ab" "a(?!b)" match-head >string ] unit-test -[ "a" ] [ "ac" "a(?!b)" match-head >string ] unit-test +[ "" ] [ "ab" "a(?!b)" first-match >string ] unit-test +[ "a" ] [ "ac" "a(?!b)" first-match >string ] unit-test [ t ] [ "fxxbar" ".{3}(?!foo)bar" matches? ] unit-test [ t ] [ "foobar" ".{3}(?!foo)bar" matches? ] unit-test [ t ] [ "fxxbar" "(?!foo).{3}bar" matches? ] unit-test [ f ] [ "foobar" "(?!foo).{3}bar" matches? ] unit-test -[ "a" ] [ "ab" "a(?=b)(?=b)" match-head >string ] unit-test -[ "a" ] [ "ba" "(?<=b)(?<=b)a" match-head >string ] unit-test -[ "a" ] [ "cab" "(?<=c)a(?=b)" match-head >string ] unit-test +[ "a" ] [ "ab" "a(?=b)(?=b)" first-match >string ] unit-test +[ "a" ] [ "ba" "(?<=b)(?<=b)a" first-match >string ] unit-test +[ "a" ] [ "cab" "(?<=c)a(?=b)" first-match >string ] unit-test -[ 3 ] [ "foobar" "foo(?=bar)" match-head length ] unit-test -[ f ] [ "foobxr" "foo(?=bar)" match-head ] unit-test +[ 3 ] [ "foobar" "foo(?=bar)" first-match length ] unit-test +[ f ] [ "foobxr" "foo(?=bar)" first-match ] unit-test ! Bug in parsing word [ t ] [ "a" R' a' matches? ] unit-test @@ -424,8 +424,12 @@ IN: regexp-tests [ 1 ] [ "a\r" R/ a$/m count-matches ] unit-test [ 1 ] [ "a\r\n" R/ a$/m count-matches ] unit-test -[ f ] [ "foobxr" "foo\\z" match-head ] unit-test -[ 3 ] [ "foo" "foo\\z" match-head length ] unit-test +[ f ] [ "foobxr" "foo\\z" first-match ] unit-test +[ 3 ] [ "foo" "foo\\z" first-match length ] unit-test + +[ t ] [ "a foo b" R/ foo/ re-contains? ] unit-test +[ f ] [ "a bar b" R/ foo/ re-contains? ] unit-test +[ t ] [ "foo" R/ foo/ re-contains? ] unit-test ! [ t ] [ "foo" "\\bfoo\\b" matches? ] unit-test ! [ t ] [ "afoob" "\\Bfoo\\B" matches? ] unit-test diff --git a/basis/regexp/regexp.factor b/basis/regexp/regexp.factor index 94bbc2af58..90218e05bd 100644 --- a/basis/regexp/regexp.factor +++ b/basis/regexp/regexp.factor @@ -89,16 +89,17 @@ PRIVATE> slices [ from>> ] map string length suffix [ string ] 2map ; -: match-head ( str regexp -- slice/f ) - [ - [ 0 ] [ check-string ] [ dup dfa>> '[ _ _ execute ] ] tri* - match-from - ] call( str regexp -- slice/f ) ; - PRIVATE> +: first-match ( string regexp -- slice/f ) + [ 0 ] [ check-string ] [ ] tri* + do-next-match nip ; + +: re-contains? ( string regexp -- ? ) + first-match >boolean ; + : re-split1 ( string regexp -- before after/f ) - dupd match-head [ 1array split-slices first2 ] [ f ] if* ; + dupd first-match [ 1array split-slices first2 ] [ f ] if* ; : re-split ( string regexp -- seq ) dupd all-matches split-slices ; From dca194e1eb8ff01fcbdd10c1038d2c2bb4507895 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Tue, 10 Mar 2009 23:21:05 -0500 Subject: [PATCH 15/17] Fixing XMode, which I gratuitiously broke --- basis/xmode/marker/marker.factor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basis/xmode/marker/marker.factor b/basis/xmode/marker/marker.factor index d3ad266b5d..f584756f33 100755 --- a/basis/xmode/marker/marker.factor +++ b/basis/xmode/marker/marker.factor @@ -3,7 +3,7 @@ USING: kernel namespaces make xmode.rules xmode.tokens xmode.marker.state xmode.marker.context xmode.utilities xmode.catalog sequences math assocs combinators strings -regexp splitting unicode.case +regexp splitting unicode.case ascii combinators.short-circuit accessors ; IN: xmode.marker @@ -84,7 +84,7 @@ M: string-matcher text-matches? ] keep string>> length and ; M: regexp text-matches? - [ >string ] dip match-head ; + [ >string ] dip re-contains? ; : rule-start-matches? ( rule -- match-count/f ) dup start>> tuck swap can-match-here? [ From 21f8ba2917a422b5830a644d579a99a8e7660ea0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 11 Mar 2009 03:17:06 -0500 Subject: [PATCH 16/17] Change another throw to rethrow in stack checker --- basis/stack-checker/backend/backend.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/stack-checker/backend/backend.factor b/basis/stack-checker/backend/backend.factor index 78f357b1cb..9e867f4fbb 100755 --- a/basis/stack-checker/backend/backend.factor +++ b/basis/stack-checker/backend/backend.factor @@ -155,7 +155,7 @@ M: object apply-object push-literal ; "cannot-infer" word-prop rethrow ; : maybe-cannot-infer ( word quot -- ) - [ [ "cannot-infer" set-word-prop ] keep throw ] recover ; inline + [ [ "cannot-infer" set-word-prop ] keep rethrow ] recover ; inline : infer-word ( word -- effect ) [ From 692b648feb31883123cc70d21759e3d61351b62a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 11 Mar 2009 03:17:30 -0500 Subject: [PATCH 17/17] Change tabular-output and smash-pane behavior to fix panes unit tests; re-organize panes code to make more words private --- basis/debugger/debugger.factor | 2 +- basis/help/markup/markup.factor | 5 +- basis/inspector/inspector.factor | 4 +- basis/io/styles/styles.factor | 2 +- basis/listener/listener.factor | 2 +- basis/prettyprint/prettyprint.factor | 2 +- basis/tools/memory/memory.factor | 7 +- basis/tools/profiler/profiler.factor | 4 +- basis/tools/threads/threads.factor | 2 +- basis/tools/vocabs/browser/browser.factor | 13 ++- basis/ui/gadgets/panes/panes-tests.factor | 24 +++- basis/ui/gadgets/panes/panes.factor | 135 +++++++++++----------- basis/ui/tools/inspector/inspector.factor | 6 +- basis/ui/tools/listener/listener.factor | 2 +- 14 files changed, 118 insertions(+), 92 deletions(-) diff --git a/basis/debugger/debugger.factor b/basis/debugger/debugger.factor index 45bc5bf50a..627fd95384 100644 --- a/basis/debugger/debugger.factor +++ b/basis/debugger/debugger.factor @@ -220,7 +220,7 @@ M: assert error. 5 line-limit set [ expect>> [ [ "Expect:" write ] with-cell pprint-cell ] with-row ] [ got>> [ [ "Got:" write ] with-cell pprint-cell ] with-row ] bi - ] tabular-output ; + ] tabular-output nl ; M: immutable summary drop "Sequence is immutable" ; diff --git a/basis/help/markup/markup.factor b/basis/help/markup/markup.factor index d4f664d6ff..188cdd1cf8 100644 --- a/basis/help/markup/markup.factor +++ b/basis/help/markup/markup.factor @@ -13,7 +13,6 @@ PREDICATE: simple-element < array SYMBOL: last-element SYMBOL: span SYMBOL: block -SYMBOL: table : last-span? ( -- ? ) last-element get span eq? ; : last-block? ( -- ? ) last-element get block eq? ; @@ -44,7 +43,7 @@ M: f print-element drop ; [ print-element ] with-default-style ; : ($block) ( quot -- ) - last-element get { f table } member? [ nl ] unless + last-element get [ nl ] when span last-element set call block last-element set ; inline @@ -218,7 +217,7 @@ ALIAS: $slot $snippet table-content-style get [ swap [ last-element off call ] tabular-output ] with-style - ] ($block) table last-element set ; inline + ] ($block) ; inline : $list ( element -- ) list-style get [ diff --git a/basis/inspector/inspector.factor b/basis/inspector/inspector.factor index 05c4dc2a94..8cab5b5ad3 100644 --- a/basis/inspector/inspector.factor +++ b/basis/inspector/inspector.factor @@ -9,7 +9,7 @@ IN: inspector SYMBOL: +number-rows+ -: summary. ( obj -- ) [ summary ] keep write-object nl ; +: print-summary ( obj -- ) [ summary ] keep write-object ; ; M: plain-writer stream-write-table - [ drop format-table [ print ] each ] with-output-stream* ; + [ drop format-table [ nl ] [ write ] interleave ] with-output-stream* ; M: plain-writer make-cell-stream 2drop ; diff --git a/basis/listener/listener.factor b/basis/listener/listener.factor index 2ee0832269..78a9c03d20 100644 --- a/basis/listener/listener.factor +++ b/basis/listener/listener.factor @@ -84,7 +84,7 @@ SYMBOL: max-stack-items bi ] with-row ] each - ] tabular-output + ] tabular-output nl ] unless-empty ; : trimmed-stack. ( seq -- ) diff --git a/basis/prettyprint/prettyprint.factor b/basis/prettyprint/prettyprint.factor index 63d7bf217a..af56a4d2d0 100644 --- a/basis/prettyprint/prettyprint.factor +++ b/basis/prettyprint/prettyprint.factor @@ -165,7 +165,7 @@ SYMBOL: pprint-string-cells? ] each ] with-row ] each - ] tabular-output ; + ] tabular-output nl ; GENERIC: see ( defspec -- ) diff --git a/basis/tools/memory/memory.factor b/basis/tools/memory/memory.factor index 9b727b48de..3d9166aafa 100644 --- a/basis/tools/memory/memory.factor +++ b/basis/tools/memory/memory.factor @@ -63,11 +63,12 @@ PRIVATE> { "" "Total" "Used" "Free" } write-headings (data-room.) ] tabular-output - nl + nl nl "==== CODE HEAP" print standard-table-style [ (code-room.) - ] tabular-output ; + ] tabular-output + nl ; : heap-stats ( -- counts sizes ) [ ] instances H{ } clone H{ } clone @@ -83,4 +84,4 @@ PRIVATE> pick at pprint-cell ] with-row ] each 2drop - ] tabular-output ; + ] tabular-output nl ; diff --git a/basis/tools/profiler/profiler.factor b/basis/tools/profiler/profiler.factor index 19646e55c2..864a637096 100644 --- a/basis/tools/profiler/profiler.factor +++ b/basis/tools/profiler/profiler.factor @@ -46,9 +46,7 @@ IN: tools.profiler profiler-usage counters ; : counters. ( assoc -- ) - standard-table-style [ - sort-values simple-table. - ] tabular-output ; + sort-values simple-table. ; : profile. ( -- ) "Call counts for all words:" print diff --git a/basis/tools/threads/threads.factor b/basis/tools/threads/threads.factor index fc4ba1f6b2..18dd8ce2b7 100644 --- a/basis/tools/threads/threads.factor +++ b/basis/tools/threads/threads.factor @@ -29,4 +29,4 @@ IN: tools.threads threads >alist sort-keys values [ [ thread. ] with-row ] each - ] tabular-output ; + ] tabular-output nl ; diff --git a/basis/tools/vocabs/browser/browser.factor b/basis/tools/vocabs/browser/browser.factor index 7896cabd2e..70588d5f21 100644 --- a/basis/tools/vocabs/browser/browser.factor +++ b/basis/tools/vocabs/browser/browser.factor @@ -66,15 +66,18 @@ C: vocab-author : describe-children ( vocab -- ) vocab-name all-child-vocabs $vocab-roots ; +: files. ( seq -- ) + snippet-style get [ + code-style get [ + [ nl ] [ [ string>> ] keep write-object ] interleave + ] with-nesting + ] with-style ; + : describe-files ( vocab -- ) vocab-files [ ] map [ "Files" $heading [ - snippet-style get [ - code-style get [ - stack. - ] with-nesting - ] with-style + files. ] ($block) ] unless-empty ; diff --git a/basis/ui/gadgets/panes/panes-tests.factor b/basis/ui/gadgets/panes/panes-tests.factor index 680b6fe57f..e486bffd38 100644 --- a/basis/ui/gadgets/panes/panes-tests.factor +++ b/basis/ui/gadgets/panes/panes-tests.factor @@ -19,7 +19,7 @@ IN: ui.gadgets.panes.tests : test-gadget-text ( quot -- ? ) dup make-pane gadget-text dup print "======" print - swap with-string-writer dup print "\n" ?tail drop "\n" ?tail drop = ; + swap with-string-writer dup print = ; [ t ] [ [ "hello" write ] test-gadget-text ] unit-test [ t ] [ [ "hello" pprint ] test-gadget-text ] unit-test @@ -87,6 +87,28 @@ IN: ui.gadgets.panes.tests ] test-gadget-text ] unit-test +[ t ] [ + [ + last-element off + \ = >link title-style get [ + $navigation-table + ] with-nesting + "Hello world" print-content + ] test-gadget-text +] unit-test + +[ t ] [ + [ { { "a\n" } } simple-table. ] test-gadget-text +] unit-test + +[ t ] [ + [ { { "a" } } simple-table. "x" write ] test-gadget-text +] unit-test + +[ t ] [ + [ H{ } [ { { "a" } } simple-table. ] with-nesting "x" write ] test-gadget-text +] unit-test + ARTICLE: "test-article-1" "This is a test article" "Hello world, how are you today." ; diff --git a/basis/ui/gadgets/panes/panes.factor b/basis/ui/gadgets/panes/panes.factor index c52c361b86..bf166f993a 100644 --- a/basis/ui/gadgets/panes/panes.factor +++ b/basis/ui/gadgets/panes/panes.factor @@ -17,6 +17,12 @@ TUPLE: pane < track output current input last-line prototype scrolls? selection-color caret mark selecting? ; +TUPLE: pane-stream pane ; + +C: pane-stream + +>caret f >>mark ; inline @@ -49,12 +55,6 @@ M: pane gadget-selection? pane-caret&mark and ; M: pane gadget-selection ( pane -- string/f ) selected-children gadget-text ; -: pane-clear ( pane -- ) - clear-selection - [ output>> clear-incremental ] - [ current>> clear-gadget ] - bi ; - : init-prototype ( pane -- pane ) +baseline+ >>align >>prototype ; inline @@ -70,17 +70,6 @@ M: pane gadget-selection ( pane -- string/f ) [ >>last-line ] [ 1 track-add ] bi dup prepare-last-line ; inline -: new-pane ( input class -- pane ) - [ vertical ] dip new-track - swap >>input - pane-theme - init-prototype - init-output - init-current - init-last-line ; inline - -: ( -- pane ) f pane new-pane ; - GENERIC: draw-selection ( loc obj -- ) : if-fits ( rect quot -- ) @@ -112,10 +101,6 @@ M: pane draw-gadget* : scroll-pane ( pane -- ) dup scrolls?>> [ scroll>bottom ] [ drop ] if ; -TUPLE: pane-stream pane ; - -C: pane-stream - : smash-line ( current -- gadget ) dup children>> { { [ dup empty? ] [ 2drop ""