From 1a3f148c2c087ebd313ebebbd1c7b45803c35d98 Mon Sep 17 00:00:00 2001
From: Slava Pestov <slava@slava-pestovs-macbook-pro.local>
Date: Mon, 1 Dec 2008 16:43:18 -0600
Subject: [PATCH 1/4] Add each-line combinator

---
 core/io/io-docs.factor | 6 ++++++
 core/io/io.factor      | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/core/io/io-docs.factor b/core/io/io-docs.factor
index c55377e4a0..02af963e1a 100644
--- a/core/io/io-docs.factor
+++ b/core/io/io-docs.factor
@@ -253,6 +253,10 @@ HELP: lines
 { $values { "stream" "an input stream" } { "seq" "a sequence of strings" } }
 { $description "Reads lines of text until the stream is exhausted, collecting them in a sequence of strings." } ;
 
+HELP: each-line
+{ $values { "quot" { $quotation "( str -- )" } } }
+{ $description "Calls the quotatin with successive lines of text, until the current " { $link input-stream } " is exhausted." } ;
+
 HELP: contents
 { $values { "stream" "an input stream" } { "str" string } }
 { $description "Reads the entire contents of a stream into a string." }
@@ -364,6 +368,8 @@ ARTICLE: "stream-utils" "Stream utilities"
 $nl
 "First, a simple composition of " { $link stream-write } " and " { $link stream-nl } ":"
 { $subsection stream-print }
+"Processing lines one by one:"
+{ $subsection each-line }
 "Sluring an entire stream into memory all at once:"
 { $subsection lines }
 { $subsection contents }
diff --git a/core/io/io.factor b/core/io/io.factor
index d7d4edf49f..c1fd69a16a 100644
--- a/core/io/io.factor
+++ b/core/io/io.factor
@@ -99,6 +99,9 @@ SYMBOL: error-stream
 : lines ( stream -- seq )
     [ [ readln dup ] [ ] [ drop ] produce ] with-input-stream ;
 
+: each-line ( quot -- )
+    [ [ readln dup ] ] dip [ drop ] while ; inline
+
 : contents ( stream -- str )
     [
         [ 65536 read dup ] [ ] [ drop ] produce concat f like

From 951ea1880435b62d42c6a809dd04d8a08350fd9b Mon Sep 17 00:00:00 2001
From: Slava Pestov <slava@slava-pestovs-macbook-pro.local>
Date: Mon, 1 Dec 2008 16:43:22 -0600
Subject: [PATCH 2/4] Minor update

---
 README.txt | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/README.txt b/README.txt
index 754791aa1a..98616539d2 100755
--- a/README.txt
+++ b/README.txt
@@ -43,13 +43,10 @@ Compilation will yield an executable named 'factor' on Unix,
 
 For X11 support, you need recent development libraries for libc,
 Freetype, X11, OpenGL and GLUT. On a Debian-derived Linux distribution
-(like Ubuntu), you can use the line
+(like Ubuntu), you can use the following line to grab everything:
 
     sudo apt-get install libc6-dev libfreetype6-dev libx11-dev glutg3-dev
 
-to grab everything (if you're on a non-debian-derived distro please tell
-us what the equivalent command is on there and it can be added).
-
 * Bootstrapping the Factor image
 
 Once you have compiled the Factor runtime, you must bootstrap the Factor

From 973e3faa0064bfa6c2f0d5d2a3f9afb5f051bf79 Mon Sep 17 00:00:00 2001
From: Slava Pestov <slava@slava-pestovs-macbook-pro.local>
Date: Mon, 1 Dec 2008 17:00:35 -0600
Subject: [PATCH 3/4] Documentation updates

---
 basis/help/cookbook/cookbook.factor | 43 +++++++++++++++++++++--------
 core/memory/memory-docs.factor      |  9 ++++--
 2 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/basis/help/cookbook/cookbook.factor b/basis/help/cookbook/cookbook.factor
index a957cb3e72..65b40543af 100644
--- a/basis/help/cookbook/cookbook.factor
+++ b/basis/help/cookbook/cookbook.factor
@@ -266,7 +266,7 @@ $nl
 "To run a script, simply pass it as an argument to the Factor executable:"
 { $code "./factor cleanup.factor" }
 "The script may access command line arguments by inspecting the value of the " { $link command-line } " variable. It can also get its own path from the " { $link script } " variable."
-$nl
+{ $heading "Example: ls" }
 "Here is an example implementing a simplified version of the Unix " { $snippet "ls" } " command in Factor:"
 { $code
     <" USING: command-line namespaces io io.files io.files.listing
@@ -282,6 +282,36 @@ command-line get [
 }
 "You can put it in a file named " { $snippet "ls.factor" } ", and then run it, to list the " { $snippet "/usr/bin" } " directory for example:"
 { $code "./factor ls.factor /usr/bin" }
+{ $heading "Example: grep" }
+"The following is a more complicated example, implementing something like the Unix " { $snippet "grep" } " command:"
+{ $code <" USING: kernel fry io io.files io.encodings.ascii sequences
+regexp command-line namespaces ;
+IN: grep
+
+: grep-lines ( pattern -- )
+    '[ dup _ matches? [ print ] [ drop ] if ] each-line ;
+
+: grep-file ( pattern filename -- )
+    ascii [ grep-lines ] with-file-reader ;
+
+: grep-usage ( -- )
+    "Usage: factor grep.factor <pattern> [<file>...]" print ;
+
+command-line get [
+    grep-usage
+] [
+    unclip <regexp> swap [
+        grep-lines
+    ] [
+        [ grep-file ] with each
+    ] if-empty
+] if-empty"> }
+"You can run it like so,"
+{ $code "./factor grep.factor '.*hello.*' myfile.txt" }
+"You'll notice this script takes a while to start. This is because it is loading and compiling the " { $vocab-link "regexp" } " vocabulary every time. To speed up startup, load the vocabulary into your image, and save the image:"
+{ $code "USE: regexp" "save" }
+"Now, the " { $snippet "grep.factor" } " script will start up much faster. See " { $link "images" } " for details."
+{ $heading "Executable scripts" }
 "It is also possible to make executable scripts. A Factor file can begin with a comment like the following:"
 { $code "#! /usr/bin/env factor" }
 "If the text file is made executable, then it can be run, assuming the " { $snippet "factor" } " binary is in your " { $snippet "$PATH" } "."
@@ -291,6 +321,7 @@ $nl
     { }
     "cli"
     "cookbook-application"
+    "images"
 } ;
 
 ARTICLE: "cookbook-philosophy" "Factor philosophy"
@@ -344,15 +375,6 @@ ARTICLE: "cookbook-pitfalls" "Pitfalls to avoid"
     { "If " { $link run-file } " throws a stack depth assertion, it means that the top-level form in the file left behind values on the stack. The stack depth is compared before and after loading a source file, since this type of situation is almost always an error. If you have a legitimate need to load a source file which returns data in some manner, define a word in the source file which produces this data on the stack and call the word after loading the file." }
 } ;
 
-ARTICLE: "cookbook-images" "Image file cookbook"
-"Factor has the ability to save the entire state of the system into an " { $emphasis "image file" } "."
-$nl
-"You can save a custom image if you find yourself loading the same libraries in every Factor session; some libraries take a little while to compile, so saving an image with those libraries loaded can save you a lot of time."
-$nl
-"For example, to save an image with the web framework loaded,"
-{ $code "USE: furnace" "save" }
-"See " { $link "images" } " for details." ;
-
 ARTICLE: "cookbook-next" "Next steps"
 "Once you have read through " { $link "first-program" } " and " { $link "cookbook" } ", the best way to keep learning Factor is to start looking at some simple example programs. Here are a few particularly nice vocabularies which should keep you busy for a little while:"
 { $list
@@ -377,7 +399,6 @@ ARTICLE: "cookbook" "Factor cookbook"
 { $subsection "cookbook-application" }
 { $subsection "cookbook-scripts" }
 { $subsection "cookbook-compiler" }
-{ $subsection "cookbook-images" }
 { $subsection "cookbook-philosophy" }
 { $subsection "cookbook-pitfalls" }
 { $subsection "cookbook-next" } ;
diff --git a/core/memory/memory-docs.factor b/core/memory/memory-docs.factor
index 8f49d882ee..bfe26823be 100644
--- a/core/memory/memory-docs.factor
+++ b/core/memory/memory-docs.factor
@@ -68,14 +68,19 @@ HELP: count-instances
 } } ;
 
 ARTICLE: "images" "Images"
-"The current image can be saved; the image contains a complete dump of all data and code in the current Factor instance:"
+"Factor has the ability to save the entire state of the system into an " { $emphasis "image file" } ". The image contains a complete dump of all data and code in the current Factor instance."
 { $subsection save }
 { $subsection save-image }
 { $subsection save-image-and-exit }
 "To start Factor with a custom image, use the " { $snippet "-i=" { $emphasis "image" } } " command line switch; see " { $link "runtime-cli-args" } "."
 $nl
+"One reason to save a custom image is if you find yourself loading the same libraries in every Factor session; some libraries take a little while to compile, so saving an image with those libraries loaded can save you a lot of time."
+$nl
+"For example, to save an image with the web framework loaded,"
+{ $code "USE: furnace" "save" }
 "New images can be created from scratch:"
 { $subsection "bootstrap.image" }
-{ $see-also "tools.memory" "tools.deploy" } ;
+"The " { $link "tools.deploy" } " tool creates stripped-down images containing just enough code to run a single application."
+{ $see-also "tools.memory" } ;
 
 ABOUT: "images"

From 87656b19e365ed51078b175926ad3e74a17ee2d0 Mon Sep 17 00:00:00 2001
From: Slava Pestov <slava@slava-pestovs-macbook-pro.local>
Date: Mon, 1 Dec 2008 17:19:47 -0600
Subject: [PATCH 4/4] FACTOR_ROOTS env var

---
 basis/environment/environment.factor  |  7 ++++++-
 basis/help/tutorial/tutorial.factor   |  2 ++
 core/vocabs/loader/loader-docs.factor | 20 ++++++++++++++------
 3 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/basis/environment/environment.factor b/basis/environment/environment.factor
index 492925c7c0..ca78c3efa7 100644
--- a/basis/environment/environment.factor
+++ b/basis/environment/environment.factor
@@ -1,7 +1,7 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: assocs combinators kernel sequences splitting system
-vocabs.loader ;
+vocabs.loader init ;
 IN: environment
 
 HOOK: os-env os ( key -- value )
@@ -25,3 +25,8 @@ HOOK: (set-os-envs) os ( seq -- )
     { [ os winnt? ] [ "environment.winnt" require ] }
     { [ os wince? ] [ ] }
 } cond
+
+[
+    "FACTOR_ROOTS" os-env os windows? ";" ":" ? split
+    [ add-vocab-root ] each
+] "environment" add-init-hook
diff --git a/basis/help/tutorial/tutorial.factor b/basis/help/tutorial/tutorial.factor
index afa16bbf8a..9ed36ac77c 100644
--- a/basis/help/tutorial/tutorial.factor
+++ b/basis/help/tutorial/tutorial.factor
@@ -13,6 +13,8 @@ $nl
 { $code "\"resource:work\" \"palindrome\" scaffold-vocab" }
 "If you look at the output, you will see that a few files were created in your ``work'' directory. The following phrase will print the full path of your work directory:"
 { $code "\"work\" resource-path ." }
+"The work directory is one of several " { $link "vocabs.roots" } " where Factor searches for vocabularies. It is possible to define new vocabulary roots; see " { $link "add-vocab-roots" } ". To keep things simple in this tutorial, we'll just use the work directory, though."
+$nl
 "Open the work directory in your file manager, and open the subdirectory named " { $snippet "palindrome" } ". Inside this subdirectory you will see a file named " { $snippet "palindrome.factor" } ". We will be editing this file."
 $nl
 "Notice that the file ends with an " { $link POSTPONE: IN: } " form telling Factor that all definitions in this source file should go into the " { $snippet "palindrome" } " vocabulary using the " { $link POSTPONE: IN: } " word:"
diff --git a/core/vocabs/loader/loader-docs.factor b/core/vocabs/loader/loader-docs.factor
index d658a8e033..bc57c48a62 100644
--- a/core/vocabs/loader/loader-docs.factor
+++ b/core/vocabs/loader/loader-docs.factor
@@ -2,6 +2,18 @@ USING: vocabs vocabs.loader.private help.markup help.syntax
 words strings io ;
 IN: vocabs.loader
 
+ARTICLE: "add-vocab-roots" "Working with code outside of the Factor source tree"
+"You can work with code outside of the Factor source tree by adding additional directories to the list of vocabulary roots."
+$nl
+"There are three ways of doing this."
+$nl
+"The first way is to use an environment variable. Factor looks at the " { $snippet "FACTOR_ROOTS" } " environment variable for a list of " { $snippet ":" } "-separated paths (on Unix) or a list of " { $snippet ";" } "-separated paths (on Windows)."
+$nl
+"The second way is to create a configuration file. You can list additional vocabulary roots in a file that Factor reads at startup:"
+{ $subsection "factor-roots" }
+"Finally, you can add vocabulary roots dynamically using a word:"
+{ $subsection add-vocab-root } ;
+
 ARTICLE: "vocabs.roots" "Vocabulary roots"
 "The vocabulary loader searches for it in one of the root directories:"
 { $subsection vocab-roots }
@@ -12,12 +24,8 @@ ARTICLE: "vocabs.roots" "Vocabulary roots"
     { { $snippet "extra" } " - additional contributed libraries." }
     { { $snippet "work" } " - a root for vocabularies which are not intended to be contributed back to Factor." }
 }
-"You can store your own vocabularies in the " { $snippet "work" } " directory. You can also store code outside of the Factor source tree by making Factor aware of it first. There are two ways of doing this."
-$nl
-"You can list additional vocabulary roots in a file that Factor reads at startup:"
-{ $subsection "factor-roots" }
-"Or you can add them dynamically using a word:"
-{ $subsection add-vocab-root } ;
+"You can store your own vocabularies in the " { $snippet "work" } " directory."
+{ $subsection "add-vocab-roots" } ;
 
 ARTICLE: "vocabs.loader" "Vocabulary loader"
 "The vocabulary loader is defined in the " { $vocab-link "vocabs.loader" } " vocabulary."