diff options
author | Araq <rumpf_a@web.de> | 2015-01-26 21:38:39 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2015-01-27 01:36:19 +0100 |
commit | 26b853923cbbd92b9b74cf1b9dce773b0ff39cf3 (patch) | |
tree | 6ccfe4b728b2469b69fe4a884f393b51dc22ab26 /compiler/nimsuggest | |
parent | 217390d18192e87534e61b9d15c55d44b7e163f7 (diff) | |
download | Nim-26b853923cbbd92b9b74cf1b9dce773b0ff39cf3.tar.gz |
nimsuggest: first version
Diffstat (limited to 'compiler/nimsuggest')
-rw-r--r-- | compiler/nimsuggest/nimsuggest.nim | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim new file mode 100644 index 000000000..b9d167beb --- /dev/null +++ b/compiler/nimsuggest/nimsuggest.nim @@ -0,0 +1,187 @@ +# +# +# The Nim Compiler +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Nimsuggest is a tool that helps to give editors IDE like capabilities. + +import strutils, os, parseopt, parseUtils +import options, commands, modules, sem, passes, passaux, msgs, nimconf, + extccomp, condsyms, lists, net, rdstdin + +const Usage = """ +Nimsuggest - Tool to give every editor IDE like capabilities for Nim +Usage: + nimsuggest [options] projectfile.nim + +Options: + --port:PORT port, by default 6000 + --address:HOST binds to that address, by default "" + --stdin read commands from stdin and write results to + stdout instead of using sockets + +The server then listens to the connection and takes line-based commands. + +In addition, all command line options of Nim that do not affect code generation +are supported. +""" + +var + gPort = 6000.Port + gAddress = "" + gUseStdin: bool + +const + seps = {':', ';', ' ', '\t'} + Help = "usage: sug|con|def|use dirtybuffer.nim[;originalfile.nim]:line:col\n"& + "type 'quit' to quit\n" & + "type 'debug' to toggle debug mode on/off\n" & + "type 'terse' to toggle terse mode on/off" + +proc parseQuoted(cmd: string; outp: var string; start: int): int = + var i = start + i += skipWhitespace(cmd, i) + if cmd[i] == '"': + i += parseUntil(cmd, outp, '"', i+1)+1 + else: + i += parseUntil(cmd, outp, seps, i) + result = i + +proc action(cmd: string) = + template toggle(sw) = + if sw in gGlobalOptions: + excl(gGlobalOptions, sw) + else: + incl(gGlobalOptions, sw) + return + + var opc = "" + var i = parseIdent(cmd, opc, 0) + case opc.normalize + of "sug": gIdeCmd = ideSug + of "con": gIdeCmd = ideCon + of "def": gIdeCmd = ideDef + of "use": + modules.resetAllModules() + gIdeCmd = ideUse + of "quit": quit() + of "debug": toggle optIdeDebug + of "terse": toggle optIdeTerse + else: + echo Help + return + var dirtyfile = "" + var orig = "" + i = parseQuoted(cmd, dirtyfile, i) + if cmd[i] == ';': + i = parseQuoted(cmd, orig, i+1) + i += skipWhile(cmd, seps, i) + var line, col = -1 + i += parseInt(cmd, line, i) + i += skipWhile(cmd, seps, i) + i += parseInt(cmd, col, i) + if dirtyfile.len != 0: + gDirtyBufferIdx = dirtyfile.fileInfoIdx + gDirtyOriginalIdx = if orig.len != 0: orig.fileInfoIdx else: gDirtyBufferIdx + else: + discard "use the same filename as in the last command" + resetModule gDirtyBufferIdx + if gDirtyBufferIdx != gProjectMainIdx: + resetModule gProjectMainIdx + gTrackPos = newLineInfo(gDirtyBufferIdx, line, col) + #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx + gErrorCounter = 0 + compileProject() + +proc serve() = + gDirtyBufferIdx = gProjectMainIdx + gDirtyOriginalIdx = gProjectMainIdx + # do not stop after the first error: + msgs.gErrorMax = high(int) + if gUseStdin: + echo Help + var line = "" + while readLineFromStdin("> ", line): + action line + echo "" + flushFile(stdout) + else: + var server = newSocket() + server.bindAddr(gPort, gAddress) + var inp = "".TaintedString + server.listen() + var stdoutSocket = newSocket() + msgs.writelnHook = proc (line: string) = + stdoutSocket.send(line & "\c\L") + while true: + accept(server, stdoutSocket) + stdoutSocket.readLine(inp) + action inp.string + stdoutSocket.send("\c\L") + stdoutSocket.close() + +proc mainCommand = + registerPass verbosePass + registerPass semPass + gCmd = cmdIdeTools + incl gGlobalOptions, optCaasEnabled + isServing = true + wantMainModule() + appendStr(searchPaths, options.libpath) + if gProjectFull.len != 0: + # current path is always looked first for modules + prependStr(searchPaths, gProjectPath) + + serve() + +proc processCmdLine*(pass: TCmdLinePass, cmd: string) = + var p = parseopt.initOptParser(cmd) + while true: + parseopt.next(p) + case p.kind + of cmdEnd: break + of cmdLongoption, cmdShortOption: + case p.key.normalize + of "port": gPort = parseInt(p.val).Port + of "address": gAddress = p.val + of "stdin": gUseStdin = true + else: processSwitch(pass, p) + of cmdArgument: + options.gProjectName = unixToNativePath(p.key) + # if processArgument(pass, p, argsCount): break + +proc handleCmdLine() = + if paramCount() == 0: + stdout.writeln(Usage) + else: + processCmdLine(passCmd1, "") + if gProjectName != "": + try: + gProjectFull = canonicalizePath(gProjectName) + except OSError: + gProjectFull = gProjectName + var p = splitFile(gProjectFull) + gProjectPath = p.dir + gProjectName = p.name + else: + gProjectPath = getCurrentDir() + loadConfigs(DefaultConfig) # load all config files + # now process command line arguments again, because some options in the + # command line can overwite the config file's settings + extccomp.initVars() + processCmdLine(passCmd2, "") + mainCommand() + +when false: + proc quitCalled() {.noconv.} = + writeStackTrace() + + addQuitProc(quitCalled) + +condsyms.initDefines() +defineSymbol "nimsuggest" +handleCmdline() |