Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

More code documentation.

  • Loading branch information...
commit 4e1f80518b87199e22bec1c75f82bd9115db4bdb 1 parent a83f5f7
Matt Brubeck authored
Showing with 37 additions and 2 deletions.
  1. +27 −1 Completer.hs
  2. +6 −0 Tokenize.hs
  3. +4 −1 Usage.hs
28 Completer.hs
View
@@ -9,49 +9,75 @@ import Control.Monad (liftM, sequence)
import Data.List (isPrefixOf)
import System.Directory (getDirectoryContents)
+-- The "Completer" type is a function that takes a list of input tokens and
+-- returns a list of possible completions. Each completion can be a new list
+-- of tokens (which will be handed to the next completer in a sequence) or
+-- an action to generate a list of strings.
+--
+-- This module provides a set of primitive completers, and combinators to build
+-- new completers through alternation, repetition, and sequencing. These are
+-- essentially identical to the parser combinators in "Monadic Parsing" by Hutton
+-- and Meijer, except that they short-circuit: if all of the input is consumed by
+-- one completer in a sequence, then the sequence returns the results of that
+-- completer, rather than failure.
+
type Completer = [String] -> [Completion]
data Completion = Tokens [String] | Suggestions (IO [String])
run :: Completer -> [String] -> IO [String]
run c ts = liftM concat $ sequence [x | Suggestions x <- c ts]
+
-- Matching
+-- Match or suggest the specified string.
str :: String -> Completer
str s = match (s ==) (\t -> if t `isPrefixOf` s then return [s ++ " "] else return [])
+-- Match anything, or suggest a list of matching files.
+-- (This is not yet fully implemented - it only looks for files in the current directory.)
file :: Completer
file = match (const True) (\t -> liftM (filter (t `isPrefixOf`)) (getDirectoryContents "."))
+-- Build a completer that looks at a single token. If more input remains then call
+-- predicate "p" to decide whether to continue. Otherwise, call fuction "suggest"
+-- to generate a list of completions.
match :: (String -> Bool) -> (String -> IO [String]) -> Completer
match p suggest ts = case ts of
[] -> []
[t] -> [Suggestions $ suggest t]
(t:ts) -> if p t then continue ts else []
--- Primitives
+-- Other primitives
+
+-- Consume nothing.
continue :: Completer
continue ts = [Tokens ts]
+-- Consume anything.
skip :: Completer
skip (t:ts) = [Tokens ts]
skip _ = []
+
-- Combinators
optional :: Completer -> Completer
optional c = c <|> continue
+-- Choice operator.
(<|>) :: Completer -> Completer -> Completer
c <|> d = \ts -> c ts ++ d ts
+-- Sequence operator.
(-->) :: Completer -> Completer -> Completer
c --> d = \ts -> concat [ case result of
Tokens ts' -> d ts'
_ -> [result]
| result <- c ts]
+-- Repetition.
many :: Completer -> Completer
many p = many1 p <|> continue
6 Tokenize.hs
View
@@ -3,6 +3,12 @@ module Tokenize (tokenize, tokens, token) where
import Data.Char (isSpace)
import Text.ParserCombinators.Parsec hiding (token, tokens)
+-- | @tokenize@
+-- Split a shell command into a list of words, attempting to use the same
+-- rules as the shell (does not yet handle certain cases like subshells).
+-- The command might be incomplete, so handle unbalanced quotes, and treat
+-- trailing whitespace as the start of an empty token.
+
tokenize :: String -> [String]
tokenize s = case runParser tokens () "" s of
Right ts -> ts
5 Usage.hs
View
@@ -5,6 +5,9 @@ import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Language (javaStyle)
import qualified Text.ParserCombinators.Parsec.Token as T
+-- This module parses the usage file format (see README for an explanation)
+-- and generates a Completer (see the Completer module).
+
data Usage = Primitive C.Completer | Var String
| Choice [Usage] | Sequence [Usage]
| Many Usage | Many1 Usage | Optional Usage
@@ -18,7 +21,7 @@ fromFile fileName = do
-- Evaluator
-type Environment = [(String,Usage)]
+type Environment = [(String,Usage)] -- Associates variables with values.
run :: Environment -> C.Completer
run env = eval env (main env)
Please sign in to comment.
Something went wrong with that request. Please try again.