define [ "auto-complete/commands" ], (commands) -> class Parser constructor: (@doc) -> parse: () -> commands = [] seen = {} while command = @nextCommand() docState = @doc optionalArgs = 0 while @consumeArgument("[", "]") optionalArgs++ args = 0 while @consumeArgument("{", "}") args++ commandHash = "#{command}\\#{optionalArgs}\\#{args}" if !seen[commandHash]? seen[commandHash] = true commands.push [command, optionalArgs, args] # Reset to before argument to handle nested commands @doc = docState return commands # Ignore single letter commands since auto complete is moot then. commandRegex: /\\([a-zA-Z][a-zA-Z]+)/ nextCommand: () -> i = @doc.search(@commandRegex) if i == -1 return false else match = @doc.match(@commandRegex)[1] @doc = @doc.substr(i + match.length + 1) return match consumeWhitespace: () -> match = @doc.match(/^[ \t\n]*/m)[0] @doc = @doc.substr(match.length) consumeArgument: (openingBracket, closingBracket) -> @consumeWhitespace() if @doc[0] == openingBracket i = 1 bracketParity = 1 while bracketParity > 0 and i < @doc.length if @doc[i] == openingBracket bracketParity++ else if @doc[i] == closingBracket bracketParity-- i++ if bracketParity == 0 @doc = @doc.substr(i) return true else return false else return false class SuggestionManager getCompletions: (editor, session, pos, prefix, callback) -> doc = session.getValue() parser = new Parser(doc) commands = parser.parse() completions = [] for command in commands caption = "\\#{command[0]}" snippet = caption i = 1 _.times command[1], () -> snippet += "[${#{i}}]" caption += "[]" i++ _.times command[2], () -> snippet += "{${#{i}}}" caption += "{}" i++ completions.push { caption: caption snippet: snippet meta: "cmd" } callback null, completions loadCommandsFromDoc: (doc) -> parser = new Parser(doc) @commands = parser.parse() getSuggestions: (commandFragment) -> matchingCommands = _.filter @commands, (command) -> command[0].slice(0, commandFragment.length) == commandFragment return _.map matchingCommands, (command) -> base = "\\" + commandFragment args = "" _.times command[1], () -> args = args + "[]" _.times command[2], () -> args = args + "{}" completionBase = command[0].slice(commandFragment.length) squareArgsNo = command[1] curlyArgsNo = command[2] totalArgs = squareArgsNo + curlyArgsNo if totalArgs == 0 completionBeforeCursor = completionBase completionAfterCurspr = "" else completionBeforeCursor = completionBase + args[0] completionAfterCursor = args.slice(1) return { base: base, completion: completionBase + args, completionBeforeCursor: completionBeforeCursor completionAfterCursor: completionAfterCursor }