diff --git a/index.html b/index.html
index c3dfe07..7aef48a 100644
--- a/index.html
+++ b/index.html
@@ -18,13 +18,7 @@
// Load KeyboardEvent polyfill for old browsers
keyboardeventKeyPolyfill.polyfill();
- var globalEnv = Insect.initialEnvironment;
-
- var commands = ["help", "list", "ls", "reset", "clear", "quit", "exit"];
-
- var functions = ["acos", "acosh", "asin", "asinh", "atan", "atanh",
- "ceil", "cos", "cosh", "exp", "floor", "ln", "log",
- "log10", "round", "sin", "sinh", "sqrt", "tan", "tanh"];
+ var insectEnv = Insect.initialEnvironment;
function interpret(line) {
// Skip empty lines or line comments
@@ -34,8 +28,8 @@
}
// Run insect
- var res = Insect.repl(Insect.fmtJqueryTerminal)(globalEnv)(line);
- globalEnv = res.newEnv;
+ var res = Insect.repl(Insect.fmtJqueryTerminal)(insectEnv)(line);
+ insectEnv = res.newEnv;
// Handle shell commands
if (res.msgType == "clear") {
@@ -45,7 +39,7 @@
} else if (res.msgType == "quit") {
// Treat as reset:
this.clear();
- globalEnv = Insect.initialEnvironment;
+ insectEnv = Insect.initialEnvironment;
return "";
}
@@ -83,10 +77,14 @@
return line.trim() !== "";
},
completion: function(inp, cb) {
- var variables = Object.keys(globalEnv);
- cb(commands.concat(functions)
+ var variables = Object.keys(insectEnv);
+
+ var keywords =
+ variables.concat(Insect.functions)
.concat(Insect.supportedUnits)
- .concat(variables));
+ .concat(Insect.commands);
+
+ cb(keywords.sort());
}
});
});
diff --git a/index.js b/index.js
index df9dfa7..ca37f7d 100755
--- a/index.js
+++ b/index.js
@@ -52,7 +52,26 @@ if (interactive) {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
- prompt: '\x1b[01m>>>\x1b[0m '
+ prompt: '\x1b[01m>>>\x1b[0m ',
+ completer: function(line) {
+ var variables = Object.keys(insectEnv);
+
+ var keywords =
+ variables.concat(Insect.functions)
+ .concat(Insect.supportedUnits)
+ .concat(Insect.commands);
+
+ var lastWord = line;
+ if (line.trim() !== "") {
+ var words = line.split(/\b/);
+ lastWord = words[words.length - 1];
+ keywords= keywords.filter(function(kw) {
+ return kw.indexOf(lastWord) === 0;
+ });
+ }
+
+ return [keywords, lastWord];
+ }
});
rl.prompt();
diff --git a/src/Insect.purs b/src/Insect.purs
index ba493dc..0c9e653 100644
--- a/src/Insect.purs
+++ b/src/Insect.purs
@@ -5,6 +5,8 @@ module Insect
, fmtPlain
, fmtJqueryTerminal
, fmtConsole
+ , commands
+ , functions
) where
import Prelude
@@ -18,6 +20,7 @@ import Text.Parsing.Parser (parseErrorPosition, parseErrorMessage)
import Insect.Parser (Dictionary(..), (==>),
normalUnitDict, imperialUnitDict, parseInsect)
+import Insect.Parser as P
import Insect.Interpreter (MessageType(..), Message(..), runInsect)
import Insect.Environment (Environment)
import Insect.Environment as E
@@ -87,3 +90,11 @@ fmtJqueryTerminal = F.fmtJqueryTerminal
-- | Re-export the console formatter
fmtConsole ∷ Formatter
fmtConsole = F.fmtConsole
+
+-- | Re-export the list of commands
+commands ∷ Array String
+commands = P.commands
+
+-- | Re-export the list of function names
+functions ∷ Array String
+functions = P.functions
diff --git a/src/Insect/Parser.purs b/src/Insect/Parser.purs
index 0bff345..ff28d3c 100644
--- a/src/Insect/Parser.purs
+++ b/src/Insect/Parser.purs
@@ -3,6 +3,8 @@ module Insect.Parser
( DictEntry(..)
, (==>)
, Dictionary(..)
+ , commands
+ , functions
, siPrefixDict
, normalUnitDict
, imperialUnitDict
@@ -26,7 +28,7 @@ import Quantities (DerivedUnit, atto, bit, byte, centi, day, deci, degree, exa,
import Data.Array (some, fromFoldable)
import Data.Either (Either(..))
import Data.Decimal (Decimal, fromString, fromNumber, isFinite)
-import Data.Foldable (foldr)
+import Data.Foldable (foldr, foldMap)
import Data.Foldable as F
import Data.List (List, many, init, last)
import Data.Maybe (Maybe(..), fromMaybe)
@@ -55,6 +57,10 @@ identStart = letter <|> char '_'
identLetter ∷ P Char
identLetter = letter <|> digit <|> char '_' <|> char '\''
+-- | A list of allowed commands
+commands ∷ Array String
+commands = ["help", "?", "list", "ls", "ll", "reset", "clear", "cls", "quit", "exit"]
+
-- | The language definition.
insectLanguage ∷ LanguageDef
insectLanguage = LanguageDef
@@ -66,8 +72,7 @@ insectLanguage = LanguageDef
, identLetter: identLetter
, opStart: oneOf ['+', '-', '*', '·', '⋅', '×', '/', '÷', '^', '=']
, opLetter: oneOf ['>', '*']
- , reservedNames: ["help", "?", "list", "ls", "reset", "clear", "cls", "quit",
- "exit", "²", "³"]
+ , reservedNames: commands <> ["²", "³"]
, reservedOpNames: ["->", "+", "-", "*", "·", "⋅", "×", "/", "÷", "^", "**",
"="]
, caseSensitive: true
@@ -269,29 +274,39 @@ derivedUnit =
variable ∷ P Expression
variable = Variable <$> token.identifier
+-- | Possible names for the mathematical functions.
+funcNameDict ∷ Dictionary Func
+funcNameDict = Dictionary
+ [ Acosh ==> ["acosh"]
+ , Acos ==> ["acos"]
+ , Asinh ==> ["asinh"]
+ , Asin ==> ["asin"]
+ , Atanh ==> ["atanh"]
+ , Atan ==> ["atan"]
+ , Ceil ==> ["ceil"]
+ , Cosh ==> ["cosh"]
+ , Cos ==> ["cos"]
+ , Exp ==> ["exp"]
+ , Floor ==> ["floor"]
+ , Log10 ==> ["log10"]
+ , Ln ==> ["log", "ln"]
+ , Round ==> ["round"]
+ , Sinh ==> ["sinh"]
+ , Sin ==> ["sin"]
+ , Sqrt ==> ["sqrt"]
+ , Tanh ==> ["tanh"]
+ , Tan ==> ["tan"]
+ ]
+
+-- | A list of all mathematical function names (for tab-completion).
+functions ∷ Array String
+functions =
+ case funcNameDict of
+ Dictionary dict → foldMap (\(_ ==> names) → names) dict
+
-- | Parse the name of a mathematical function.
funcName ∷ P Func
-funcName =
- (string "acosh" *> pure Acosh)
- <|> (string "acos" *> pure Acos)
- <|> (string "asinh" *> pure Asinh)
- <|> (string "asin" *> pure Asin)
- <|> (string "atanh" *> pure Atanh)
- <|> (string "atan" *> pure Atan)
- <|> (string "ceil" *> pure Ceil)
- <|> (string "cosh" *> pure Cosh)
- <|> (string "cos" *> pure Cos)
- <|> (string "exp" *> pure Exp)
- <|> (string "floor" *> pure Floor)
- <|> (string "log10" *> pure Log10)
- <|> (string "log" *> pure Ln)
- <|> (string "ln" *> pure Ln)
- <|> (string "round" *> pure Round)
- <|> (string "sinh" *> pure Sinh)
- <|> (string "sin" *> pure Sin)
- <|> (string "sqrt" *> pure Sqrt)
- <|> (string "tanh" *> pure Tanh)
- <|> (string "tan" *> pure Tan)
+funcName = buildDictParser funcNameDict > "function name"
-- | A version of `sepBy1` that returns a `NonEmpty List`.
sepBy1 ∷ ∀ m s a sep. Monad m ⇒ ParserT s m a → ParserT s m sep → ParserT s m (NonEmpty List a)
@@ -390,7 +405,7 @@ command ∷ P Command
command =
(
(reserved "help" <|> reserved "?") *> pure Help
- <|> (reserved "list" <|> reserved "ls") *> pure List
+ <|> (reserved "list" <|> reserved "ls" <|> reserved "ll") *> pure List
<|> (reserved "reset") *> pure Reset
<|> (reserved "clear" <|> reserved "cls") *> pure Clear
<|> (reserved "quit" <|> reserved "exit") *> pure Quit
diff --git a/test/Main.purs b/test/Main.purs
index 8ee5027..c9112b2 100644
--- a/test/Main.purs
+++ b/test/Main.purs
@@ -581,7 +581,7 @@ main = runTest do
expectOutput myEnv "10m" "2 x"
expectOutput myEnv "25m²" "x x"
expectOutput myEnv "25m²" "x²"
- expectOutput myEnv "Unknown variable 'x2'" "x2"
+ expectOutput myEnv "Unknown identifier: x2" "x2"
test "Function inverses" do
expectOutput' "0.1234" "sin(asin(0.1234))"