summary refs log tree commit diff stats
path: root/compiler/nimsuggest
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2015-01-26 21:38:39 +0100
committerAraq <rumpf_a@web.de>2015-01-27 01:36:19 +0100
commit26b853923cbbd92b9b74cf1b9dce773b0ff39cf3 (patch)
tree6ccfe4b728b2469b69fe4a884f393b51dc22ab26 /compiler/nimsuggest
parent217390d18192e87534e61b9d15c55d44b7e163f7 (diff)
downloadNim-26b853923cbbd92b9b74cf1b9dce773b0ff39cf3.tar.gz
nimsuggest: first version
Diffstat (limited to 'compiler/nimsuggest')
-rw-r--r--compiler/nimsuggest/nimsuggest.nim187
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()