Removed nimsuggest from this repo.
This commit is contained in:
parent
4a7c0e8872
commit
4b0089bf58
2 changed files with 2 additions and 343 deletions
|
|
@ -7,330 +7,6 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## Nimsuggest is a tool that helps to give editors IDE like capabilities.
|
## Nimsuggest has been moved to https://github.com/nim-lang/nimsuggest
|
||||||
|
|
||||||
import strutils, os, parseopt, parseutils, sequtils, net
|
{.error: "This project has moved to the following repo: https://github.com/nim-lang/nimsuggest".}
|
||||||
# Do NOT import suggest. It will lead to wierd bugs with
|
|
||||||
# suggestionResultHook, because suggest.nim is included by sigmatch.
|
|
||||||
# So we import that one instead.
|
|
||||||
import options, commands, modules, sem, passes, passaux, msgs, nimconf,
|
|
||||||
extccomp, condsyms, lists, net, rdstdin, sexp, sigmatch, ast
|
|
||||||
|
|
||||||
when defined(windows):
|
|
||||||
import winlean
|
|
||||||
else:
|
|
||||||
import posix
|
|
||||||
|
|
||||||
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
|
|
||||||
--epc use emacs epc mode
|
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
type
|
|
||||||
Mode = enum mstdin, mtcp, mepc
|
|
||||||
|
|
||||||
var
|
|
||||||
gPort = 6000.Port
|
|
||||||
gAddress = ""
|
|
||||||
gMode: Mode
|
|
||||||
|
|
||||||
const
|
|
||||||
seps = {':', ';', ' ', '\t'}
|
|
||||||
Help = "usage: sug|con|def|use file.nim[;dirtyfile.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"
|
|
||||||
|
|
||||||
type
|
|
||||||
EUnexpectedCommand = object of Exception
|
|
||||||
|
|
||||||
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)+2
|
|
||||||
else:
|
|
||||||
i += parseUntil(cmd, outp, seps, i)
|
|
||||||
result = i
|
|
||||||
|
|
||||||
proc sexp(s: IdeCmd): SexpNode = sexp($s)
|
|
||||||
|
|
||||||
proc sexp(s: TSymKind): SexpNode = sexp($s)
|
|
||||||
|
|
||||||
proc sexp(s: Suggest): SexpNode =
|
|
||||||
# If you change the oder here, make sure to change it over in
|
|
||||||
# nim-mode.el too.
|
|
||||||
result = convertSexp([
|
|
||||||
s.section,
|
|
||||||
s.symkind,
|
|
||||||
s.qualifiedPath.map(newSString),
|
|
||||||
s.filePath,
|
|
||||||
s.forth,
|
|
||||||
s.line,
|
|
||||||
s.column,
|
|
||||||
s.doc
|
|
||||||
])
|
|
||||||
|
|
||||||
proc sexp(s: seq[Suggest]): SexpNode =
|
|
||||||
result = newSList()
|
|
||||||
for sug in s:
|
|
||||||
result.add(sexp(sug))
|
|
||||||
|
|
||||||
proc listEPC(): SexpNode =
|
|
||||||
let
|
|
||||||
argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol))
|
|
||||||
docstring = sexp("line starts at 1, column at 0, dirtyfile is optional")
|
|
||||||
result = newSList()
|
|
||||||
for command in ["sug", "con", "def", "use"]:
|
|
||||||
let
|
|
||||||
cmd = sexp(command)
|
|
||||||
methodDesc = newSList()
|
|
||||||
methodDesc.add(cmd)
|
|
||||||
methodDesc.add(argspecs)
|
|
||||||
methodDesc.add(docstring)
|
|
||||||
result.add(methodDesc)
|
|
||||||
|
|
||||||
proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int) =
|
|
||||||
gIdeCmd = cmd
|
|
||||||
if cmd == ideUse:
|
|
||||||
modules.resetAllModules()
|
|
||||||
var isKnownFile = true
|
|
||||||
let dirtyIdx = file.fileInfoIdx(isKnownFile)
|
|
||||||
|
|
||||||
if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
|
|
||||||
else: msgs.setDirtyFile(dirtyIdx, nil)
|
|
||||||
|
|
||||||
resetModule dirtyIdx
|
|
||||||
if dirtyIdx != gProjectMainIdx:
|
|
||||||
resetModule gProjectMainIdx
|
|
||||||
|
|
||||||
gTrackPos = newLineInfo(dirtyIdx, line, col)
|
|
||||||
gErrorCounter = 0
|
|
||||||
if not isKnownFile:
|
|
||||||
compileProject()
|
|
||||||
compileProject(dirtyIdx)
|
|
||||||
|
|
||||||
proc executeEPC(cmd: IdeCmd, args: SexpNode) =
|
|
||||||
let
|
|
||||||
file = args[0].getStr
|
|
||||||
line = args[1].getNum
|
|
||||||
column = args[2].getNum
|
|
||||||
var dirtyfile = ""
|
|
||||||
if len(args) > 3:
|
|
||||||
dirtyfile = args[3].getStr(nil)
|
|
||||||
execute(cmd, file, dirtyfile, int(line), int(column))
|
|
||||||
|
|
||||||
proc returnEPC(socket: var Socket, uid: BiggestInt, s: SexpNode, return_symbol = "return") =
|
|
||||||
let response = $convertSexp([newSSymbol(return_symbol), uid, s])
|
|
||||||
socket.send(toHex(len(response), 6))
|
|
||||||
socket.send(response)
|
|
||||||
|
|
||||||
proc connectToNextFreePort(server: Socket, host: string, start = 30000): int =
|
|
||||||
result = start
|
|
||||||
while true:
|
|
||||||
try:
|
|
||||||
server.bindaddr(Port(result), host)
|
|
||||||
return
|
|
||||||
except OsError:
|
|
||||||
when defined(windows):
|
|
||||||
let checkFor = WSAEADDRINUSE.OSErrorCode
|
|
||||||
else:
|
|
||||||
let checkFor = EADDRINUSE.OSErrorCode
|
|
||||||
if osLastError() != checkFor:
|
|
||||||
raise getCurrentException()
|
|
||||||
else:
|
|
||||||
result += 1
|
|
||||||
|
|
||||||
proc parseCmdLine(cmd: string) =
|
|
||||||
template toggle(sw) =
|
|
||||||
if sw in gGlobalOptions:
|
|
||||||
excl(gGlobalOptions, sw)
|
|
||||||
else:
|
|
||||||
incl(gGlobalOptions, sw)
|
|
||||||
return
|
|
||||||
|
|
||||||
template err() =
|
|
||||||
echo Help
|
|
||||||
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": gIdeCmd = ideUse
|
|
||||||
of "quit": quit()
|
|
||||||
of "debug": toggle optIdeDebug
|
|
||||||
of "terse": toggle optIdeTerse
|
|
||||||
else: err()
|
|
||||||
var dirtyfile = ""
|
|
||||||
var orig = ""
|
|
||||||
i = parseQuoted(cmd, orig, i)
|
|
||||||
if cmd[i] == ';':
|
|
||||||
i = parseQuoted(cmd, dirtyfile, i+1)
|
|
||||||
i += skipWhile(cmd, seps, i)
|
|
||||||
var line = -1
|
|
||||||
var col = 0
|
|
||||||
i += parseInt(cmd, line, i)
|
|
||||||
i += skipWhile(cmd, seps, i)
|
|
||||||
i += parseInt(cmd, col, i)
|
|
||||||
|
|
||||||
execute(gIdeCmd, orig, dirtyfile, line, col-1)
|
|
||||||
|
|
||||||
proc serve() =
|
|
||||||
case gMode:
|
|
||||||
of mstdin:
|
|
||||||
echo Help
|
|
||||||
var line = ""
|
|
||||||
while readLineFromStdin("> ", line):
|
|
||||||
parseCmdLine line
|
|
||||||
echo ""
|
|
||||||
flushFile(stdout)
|
|
||||||
of mtcp:
|
|
||||||
var server = newSocket()
|
|
||||||
server.bindAddr(gPort, gAddress)
|
|
||||||
var inp = "".TaintedString
|
|
||||||
server.listen()
|
|
||||||
|
|
||||||
while true:
|
|
||||||
var stdoutSocket = newSocket()
|
|
||||||
msgs.writelnHook = proc (line: string) =
|
|
||||||
stdoutSocket.send(line & "\c\L")
|
|
||||||
|
|
||||||
accept(server, stdoutSocket)
|
|
||||||
|
|
||||||
stdoutSocket.readLine(inp)
|
|
||||||
parseCmdLine inp.string
|
|
||||||
|
|
||||||
stdoutSocket.send("\c\L")
|
|
||||||
stdoutSocket.close()
|
|
||||||
of mepc:
|
|
||||||
var server = newSocket()
|
|
||||||
let port = connectToNextFreePort(server, "localhost")
|
|
||||||
var inp = "".TaintedString
|
|
||||||
server.listen()
|
|
||||||
echo(port)
|
|
||||||
var client = newSocket()
|
|
||||||
# Wait for connection
|
|
||||||
accept(server, client)
|
|
||||||
while true:
|
|
||||||
var sizeHex = ""
|
|
||||||
if client.recv(sizeHex, 6) != 6:
|
|
||||||
raise newException(ValueError, "didn't get all the hexbytes")
|
|
||||||
var size = 0
|
|
||||||
if parseHex(sizeHex, size) == 0:
|
|
||||||
raise newException(ValueError, "invalid size hex: " & $sizeHex)
|
|
||||||
var messageBuffer = ""
|
|
||||||
if client.recv(messageBuffer, size) != size:
|
|
||||||
raise newException(ValueError, "didn't get all the bytes")
|
|
||||||
let
|
|
||||||
message = parseSexp($messageBuffer)
|
|
||||||
messageType = message[0].getSymbol
|
|
||||||
case messageType:
|
|
||||||
of "call":
|
|
||||||
var results: seq[Suggest] = @[]
|
|
||||||
suggestionResultHook = proc (s: Suggest) =
|
|
||||||
results.add(s)
|
|
||||||
|
|
||||||
let
|
|
||||||
uid = message[1].getNum
|
|
||||||
cmd = parseIdeCmd(message[2].getSymbol)
|
|
||||||
args = message[3]
|
|
||||||
executeEPC(cmd, args)
|
|
||||||
returnEPC(client, uid, sexp(results))
|
|
||||||
of "return":
|
|
||||||
raise newException(EUnexpectedCommand, "no return expected")
|
|
||||||
of "return-error":
|
|
||||||
raise newException(EUnexpectedCommand, "no return expected")
|
|
||||||
of "epc-error":
|
|
||||||
stderr.writeln("recieved epc error: " & $messageBuffer)
|
|
||||||
raise newException(IOError, "epc error")
|
|
||||||
of "methods":
|
|
||||||
returnEPC(client, message[1].getNum, listEPC())
|
|
||||||
else:
|
|
||||||
raise newException(EUnexpectedCommand, "unexpected call: " & messageType)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
# do not stop after the first error:
|
|
||||||
msgs.gErrorMax = high(int)
|
|
||||||
compileProject()
|
|
||||||
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
|
|
||||||
gMode = mtcp
|
|
||||||
of "address":
|
|
||||||
gAddress = p.val
|
|
||||||
gMode = mtcp
|
|
||||||
of "stdin": gMode = mstdin
|
|
||||||
of "epc":
|
|
||||||
gMode = mepc
|
|
||||||
gVerbosity = 0 # Port number gotta be first.
|
|
||||||
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()
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
# Special configuration file for the Nim project
|
|
||||||
|
|
||||||
gc:markAndSweep
|
|
||||||
|
|
||||||
hint[XDeclaredButNotUsed]:off
|
|
||||||
path:"$projectPath/../.."
|
|
||||||
|
|
||||||
path:"$lib/packages/docutils"
|
|
||||||
path:"../../compiler"
|
|
||||||
|
|
||||||
define:useStdoutAsStdmsg
|
|
||||||
define:nimsuggest
|
|
||||||
|
|
||||||
cs:partial
|
|
||||||
#define:useNodeIds
|
|
||||||
define:booting
|
|
||||||
#define:noDocgen
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue