diff --git a/README.md b/README.md index c26e8c7..c3d9505 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,27 @@ The D Completion Daemon is an auto-complete program for the D programming langua ![Teaser](teaser.png "This is what the future looks like - Jayce, League of Legends") #Status +*This program is still in an alpha state.* + * Working: * Autocompletion of properties of built-in types such as int, float, double, etc. * Autocompletion of __traits, scope, and extern arguments * Autocompletion of enums -* Crashes frequently - * Autocompletion of class, struct, and interface instances. + * Autocompletion of class, struct, and interface instances. + * Display of call tips (but only for the first overload) * Not working: - * Everything else + * UFCS + * Templates + * *auto* declarations + * Operator overloading (opIndex, opSlice, etc) when autocompleting + * Instances of enum types resolve to the enum itself instead of the enum base type + * Function parameters do not appear in the scope of the function body + * Public imports + * That one feature that you *REALLY* needed #Setup -Don't. This code is not ready for you to use yet. If you're going to ignore this -warning, be sure to run ```git submodule update --init``` after cloning this -repository to grab the MessagePack library. +1. Run ```git submodule update --init``` after cloning this repository to grab the MessagePack library. +1. The build script assumes that the DScanner project is cloned into a sibling folder. (i.e. "../dscanner" should exist). +1. Modify the server.d file because several import paths are currently hard-coded. (See also: the warning at the beginnig that this is alpha-quality) +1. Configure your text editor to call the dcd-client program +1. Start the dcd-server program before editing code. diff --git a/actypes.d b/actypes.d index 893fa82..1d8eb14 100644 --- a/actypes.d +++ b/actypes.d @@ -23,6 +23,22 @@ import stdx.d.ast; import std.algorithm; import std.stdio; import messages; +import autocomplete; + +/** + * Any special information about a variable declaration symbol. + */ +enum SymbolQualifier +{ + /// _none + none, + /// the symbol is an _array + array, + /// the symbol is a associative array + assocArray, + /// the symbol is a function or delegate pointer + func +} /** * Autocompletion symbol @@ -31,21 +47,34 @@ class ACSymbol { public: - this() - { - } + this() {} + /** + * Params: + * name = the symbol's name + */ this(string name) { this.name = name; } + /** + * Params: + * name = the symbol's name + * kind = the symbol's completion kind + */ this(string name, CompletionKind kind) { this.name = name; this.kind = kind; } + /** + * Params: + * name = the symbol's name + * kind = the symbol's completion kind + * resolvedType = the resolved type of the symbol + */ this(string name, CompletionKind kind, ACSymbol resolvedType) { this.name = name; @@ -64,8 +93,16 @@ public: */ string name; + /** + * Symbol's location in bytes + */ size_t location; + /** + * Any special information about this symbol + */ + SymbolQualifier qualifier; + /** * The kind of symbol */ @@ -78,8 +115,19 @@ public: */ Type type; + /** + * The symbol that represents the type. _resolvedType is an autocomplete + * class, type is an AST class, so after a module is parsed the symbols + * need to be post-processed to tie variable declarations to the symbols + * that actually contain the correct autocomplete information. + */ ACSymbol resolvedType; + /** + * Calltip to display if this is a function + */ + string calltip; + /** * Finds symbol parts by name */ @@ -162,30 +210,75 @@ public: return null; } + /** + * Fills in the $(D resolvedType) fields of the symbols in this scope and + * all child scopes. + */ void resolveSymbolTypes() { - foreach (s; symbols.filter!(a => a.kind == CompletionKind.variableName)()) + // We only care about resolving types of variables, all other symbols + // don't have any indirection + // TODO: Resolve types of enum members + foreach (ref s; symbols.filter!(a => (a.kind == CompletionKind.variableName + || a.kind == CompletionKind.functionName + || a.kind == CompletionKind.memberVariableName) && a.resolvedType is null)()) { + writeln("Resolving type of symbol ", s.name); Type type = s.type; - if (type.typeSuffixes.length == 0) - { + if (type is null) + continue; if (type.type2.builtinType != TokenType.invalid) { + // This part is easy. Autocomplete properties of built-in types s.resolvedType = findSymbolInCurrentScope(s.location, getTokenValue(type.type2.builtinType)); } else if (type.type2.symbol !is null) { + // Look up a type by its name for cases like class, enum, + // interface, struct, or union members. + + // TODO: Does not work with qualified names or template instances Symbol sym = type.type2.symbol; if (sym.identifierOrTemplateChain.identifiersOrTemplateInstances.length != 1) return; s.resolvedType = findSymbolInCurrentScope(s.location, sym.identifierOrTemplateChain.identifiersOrTemplateInstances[0].identifier.value); } + foreach (suffix; type.typeSuffixes) + { + // Handle type suffixes for declarations, e.g.: + // int[] a; + // SomeClass[string] b; + // double function(double, double) c; + auto sym = s.resolvedType; + s.resolvedType = new ACSymbol; + s.resolvedType.resolvedType = sym; + if (suffix.array) + { + if (suffix.type !is null) + { + // assocative array + s.resolvedType.qualifier = SymbolQualifier.assocArray; + s.resolvedType.parts ~= assocArraySymbols; + } + else + { + // ormal array + s.resolvedType.qualifier = SymbolQualifier.array; + s.resolvedType.parts ~= arraySymbols; + } + } + else if (suffix.delegateOrFunction.type != TokenType.invalid) + { + // TODO: figure out how to handle this, if necessary + s.resolvedType.qualifier = SymbolQualifier.func; + } } } foreach (c; children) { + assert (c !is null); c.resolveSymbolTypes(); } } diff --git a/acvisitor.d b/acvisitor.d index adb5997..bcb8c57 100644 --- a/acvisitor.d +++ b/acvisitor.d @@ -32,6 +32,15 @@ class AutocompleteVisitor : ASTVisitor { alias ASTVisitor.visit visit; + override void visit(Unittest dec) + { + auto symbol = new ACSymbol("*unittest*"); + auto p = parentSymbol; + parentSymbol = symbol; + dec.accept(this); + parentSymbol = p; + } + override void visit(StructDeclaration dec) { auto symbol = new ACSymbol; @@ -66,12 +75,14 @@ class AutocompleteVisitor : ASTVisitor scope_.symbols ~= new ACSymbol("this", CompletionKind.variableName, parentSymbol); scope_.parent = s; + s.children ~= scope_; structBody.accept(this); scope_ = s; } override void visit(EnumDeclaration dec) { + // TODO: Store type auto symbol = new ACSymbol; symbol.name = dec.name.value; symbol.location = dec.name.startIndex; @@ -81,10 +92,17 @@ class AutocompleteVisitor : ASTVisitor override void visit(FunctionDeclaration dec) { - auto symbol = new ACSymbol; + // TODO: Parameters need to be added to the function body scope + ACSymbol symbol = new ACSymbol; symbol.name = dec.name.value; symbol.location = dec.name.startIndex; symbol.kind = CompletionKind.functionName; + symbol.type = dec.returnType; + if (dec.returnType !is null) + { + symbol.calltip = format("%s %s%s", dec.returnType.toString(), + dec.name.value, dec.parameters.toString()); + } mixin (visitAndAdd); } @@ -117,6 +135,7 @@ class AutocompleteVisitor : ASTVisitor override void visit(ImportDeclaration dec) { + // TODO: handle public imports if (!currentFile) return; foreach (singleImport; dec.singleImports) { diff --git a/autocomplete.d b/autocomplete.d index b9a9cfb..76d2ac6 100644 --- a/autocomplete.d +++ b/autocomplete.d @@ -47,7 +47,7 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths) auto sortedTokens = assumeSorted(tokenArray); auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition); - if (beforeTokens[$ - 1] == TokenType.lParen && beforeTokens.length >= 2) + if (beforeTokens[$ - 1] == TokenType.lParen && beforeTokens.length >= 2) { immutable(string)[] completions; switch (beforeTokens[$ - 2].type) @@ -74,14 +74,15 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths) response.completionKinds ~= CompletionKind.keyword; } break; - /+case TokenType.identifier: + case TokenType.identifier: case TokenType.rParen: case TokenType.rBracket: - auto expression = getExpression(beforeTokens[0..$]); - writeln("Expression: ", expression.map!"a.value"()); - response.completionType = CompletionType.calltips; - // TODO - break;+/ + auto visitor = processModule(tokenArray); + visitor.scope_.symbols ~= builtinSymbols; + auto expression = getExpression(beforeTokens[0 .. $ - 1]); + response.setCompletions(visitor, expression, request.cursorPosition, + CompletionType.calltips); + break; default: break; } @@ -124,8 +125,9 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths) case TokenType.this_: auto visitor = processModule(tokenArray); visitor.scope_.symbols ~= builtinSymbols; - auto expression = getExpression(beforeTokens[0..$]); - response.setCompletions(visitor, expression, request.cursorPosition); + auto expression = getExpression(beforeTokens[0 .. $ - 1]); + response.setCompletions(visitor, expression, request.cursorPosition, + CompletionType.identifiers); break; case TokenType.lParen: case TokenType.lBrace: @@ -143,10 +145,11 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths) } void setCompletions(T)(ref AutocompleteResponse response, - AutocompleteVisitor visitor, T tokens, size_t cursorPosition) + AutocompleteVisitor visitor, T tokens, size_t cursorPosition, + CompletionType completionType) { - // TODO: Completely hacked together. writeln("Getting completions for ", map!"a.value"(tokens)); + writeln("Resolving symbols for editor buffer"); visitor.scope_.resolveSymbolTypes(); ACSymbol symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value); if (symbol is null) @@ -155,7 +158,8 @@ void setCompletions(T)(ref AutocompleteResponse response, return; } - if (symbol.kind == CompletionKind.memberVariableName + if (completionType == CompletionType.identifiers + && symbol.kind == CompletionKind.memberVariableName || symbol.kind == CompletionKind.variableName) { symbol = symbol.resolvedType; @@ -198,9 +202,22 @@ void setCompletions(T)(ref AutocompleteResponse response, break loop; break; case identifier: + writeln("looking for ", tokens[i].value, " in ", symbol.name); symbol = symbol.getPartByName(tokens[i].value); if (symbol is null) + { + writeln("Couldn't find it."); break loop; + } + if (symbol.kind == CompletionKind.variableName + || symbol.kind == CompletionKind.memberVariableName + || (symbol.kind == CompletionKind.functionName + && (completionType == CompletionType.identifiers + || i + 1 < tokens.length))) + { + + symbol = symbol.resolvedType; + } break; case lParen: open = TokenType.lParen; @@ -209,6 +226,17 @@ void setCompletions(T)(ref AutocompleteResponse response, case lBracket: open = TokenType.lBracket; close = TokenType.rBracket; + // TODO: handle slicing + // TODO: handle opIndex + // TODO: handle opSlice + if (symbol.qualifier == SymbolQualifier.array + || symbol.qualifier == SymbolQualifier.assocArray) + { + symbol = symbol.resolvedType; + goto skip; + } + else + return; skip: i++; for (int depth = 1; depth > 0 && i < tokens.length; i++) @@ -223,18 +251,34 @@ void setCompletions(T)(ref AutocompleteResponse response, } break; case dot: - default: break; + default: + break loop; } } - - foreach (s; symbol.parts) + if (symbol is null) { - //writeln("Adding ", s.name, " to the completion list"); - response.completionKinds ~= s.kind; - response.completions ~= s.name; + writeln("Could not get completions"); + return; } - response.completionType = CompletionType.identifiers; + if (completionType == CompletionType.identifiers) + { + writeln("Writing out the parts of ", symbol.name); + foreach (s; symbol.parts) + { + //writeln("Adding ", s.name, " to the completion list"); + response.completionKinds ~= s.kind; + response.completions ~= s.name; + } + response.completionType = CompletionType.identifiers; + } + else + { + writeln("Adding calltip for ", symbol.name, ": ", symbol.calltip); + response.completions ~= symbol.calltip; + response.completionType = CompletionType.calltips; + } + } T getExpression(T)(T beforeTokens) @@ -316,7 +360,7 @@ T getExpression(T)(T beforeTokens) else i--; } - return beforeTokens[i .. $ - 1]; + return beforeTokens[i .. $]; } string createCamelCaseRegex(string input) @@ -386,8 +430,8 @@ static this() assocArraySymbols ~= new ACSymbol("length", CompletionKind.keyword, ulong_); assocArraySymbols ~= mangleof_; assocArraySymbols ~= new ACSymbol("rehash", CompletionKind.keyword); - arraySymbols ~= sizeof_; - arraySymbols ~= stringof_; + assocArraySymbols ~= sizeof_; + assocArraySymbols ~= stringof_; assocArraySymbols ~= new ACSymbol("values", CompletionKind.keyword); foreach (s; [bool_, int_, long_, byte_, dchar_, short_, ubyte_, uint_, diff --git a/client.d b/client.d index 2692940..b90f188 100644 --- a/client.d +++ b/client.d @@ -33,11 +33,13 @@ int main(string[] args) ushort port = 9166; bool help; bool shutdown; + bool clearCache; try { getopt(args, "cursorPos|c", &cursorPos, "I", &importPaths, - "port|p", &port, "help|h", &help, "shutdown", &shutdown); + "port|p", &port, "help|h", &help, "shutdown", &shutdown, + "clearCache", &clearCache); } catch (Exception e) { @@ -50,10 +52,13 @@ int main(string[] args) return 0; } - if (shutdown) + if (shutdown || clearCache) { AutocompleteRequest request; + if (shutdown) request.kind = RequestKind.shutdown; + else if (clearCache) + request.kind = RequestKind.clearCache; auto socket = new TcpSocket(AddressFamily.INET); scope (exit) { socket.shutdown(SocketShutdown.BOTH); socket.close(); } socket.connect(new InternetAddress("127.0.0.1", port)); @@ -112,7 +117,7 @@ int main(string[] args) AutocompleteResponse response; msgpack.unpack(buffer[0..bytesReceived], response); - writeln(response.completionType); + //writeln(response.completionType); if (response.completionType == CompletionType.identifiers) { for (size_t i = 0; i < response.completions.length; i++) diff --git a/editors/emacs/README.md b/editors/emacs/README.md new file mode 100644 index 0000000..a80814c --- /dev/null +++ b/editors/emacs/README.md @@ -0,0 +1 @@ +#EMACS Integration diff --git a/editors/sublimetext2/README.md b/editors/sublimetext2/README.md new file mode 100644 index 0000000..8b2dbdf --- /dev/null +++ b/editors/sublimetext2/README.md @@ -0,0 +1 @@ +#Sublime Text 2 Integration diff --git a/editors/textadept/README.md b/editors/textadept/README.md new file mode 100644 index 0000000..ae28843 --- /dev/null +++ b/editors/textadept/README.md @@ -0,0 +1,15 @@ +#Textadept Integration + +###Installation +1. Copy the dcd.lua file into your ~/.textadept/modules/dmd/ folder +2. Modify your ~/.textadept/modules/dmd/init.lua file: + + 1. Require the dcd module + + _M.dcd = require "dmd.dcd" + + 2. Register the autocomplete function + + events.connect(events.CHAR_ADDED, function(ch) + _M.dcd.autocomplete(ch) + end) diff --git a/editors/textadept/class.png b/editors/textadept/class.png new file mode 100644 index 0000000..c992692 Binary files /dev/null and b/editors/textadept/class.png differ diff --git a/editors/textadept/class.xpm b/editors/textadept/class.xpm new file mode 100755 index 0000000..7576c38 --- /dev/null +++ b/editors/textadept/class.xpm @@ -0,0 +1,37 @@ +/* XPM */ +static char * class_xpm[] = { +"16 16 18 1", +" c None", +". c #006AD6", +"+ c #006DDC", +"@ c #0070E2", +"# c #F0F0F0", +"$ c #0072E6", +"% c #F5F5F5", +"& c #0075EC", +"* c #FBFBFB", +"= c #F7F7F7", +"- c #0073E8", +"; c #F2F2F2", +"> c #006EDE", +", c #ECECEC", +"' c #006BD8", +") c #E7E7E7", +"! c #0069D4", +"~ c #0066CE", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@@#####@@@ ", +" $$$%%%%%%%$$ ", +" &&***&&&**&& ", +" &&==&&&&&&&& ", +" --==-------- ", +" @@;;;@@@;;@@ ", +" >>>,,,,,,,>> ", +" '''')))))''' ", +" !!!!!!!!!!!! ", +" ~~~~~~~~~~ ", +" ", +" "}; diff --git a/editors/textadept/enum_dec.xpm b/editors/textadept/enum_dec.xpm new file mode 100644 index 0000000..76b43eb --- /dev/null +++ b/editors/textadept/enum_dec.xpm @@ -0,0 +1,37 @@ +/* XPM */ +static char * enum_dec_xpm[] = { +"16 16 18 1", +" c None", +". c #6D43C0", +"+ c #754EC3", +"@ c #7751C4", +"# c #F0F0F0", +"$ c #7852C5", +"% c #FFFFFF", +"& c #F5F5F5", +"* c #7D58C7", +"= c #FBFBFB", +"- c #FDFDFD", +"; c #F7F7F7", +"> c #F2F2F2", +", c #ECECEC", +"' c #7048C2", +") c #E7E7E7", +"! c #6A40BF", +"~ c #673EBA", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@######@@@ ", +" $$$%&&&&&$$$ ", +" ***==******* ", +" ***-----**** ", +" $$$;;;;;$$$$ ", +" @@@>>@@@@@@@ ", +" +++,,,,,,+++ ", +" '''))))))''' ", +" !!!!!!!!!!!! ", +" ~~~~~~~~~~ ", +" ", +" "}; diff --git a/editors/textadept/function.xpm b/editors/textadept/function.xpm new file mode 100755 index 0000000..7232e42 --- /dev/null +++ b/editors/textadept/function.xpm @@ -0,0 +1,36 @@ +/* XPM */ +static char * function_xpm[] = { +"16 16 17 1", +" c None", +". c #317025", +"+ c #367B28", +"@ c #387F2A", +"# c #F0F0F0", +"$ c #FFFFFF", +"% c #F5F5F5", +"& c #3A832C", +"* c #FBFBFB", +"= c #FDFDFD", +"- c #F7F7F7", +"; c #F2F2F2", +"> c #ECECEC", +", c #347627", +"' c #E7E7E7", +") c #306D24", +"! c #2F6A23", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@######@@@ ", +" @@@$%%%%%@@@ ", +" &&&**&&&&&&& ", +" &&&=====&&&& ", +" @@@-----@@@@ ", +" @@@;;@@@@@@@ ", +" +++>>+++++++ ", +" ,,,'',,,,,,, ", +" )))))))))))) ", +" !!!!!!!!!! ", +" ", +" "}; diff --git a/editors/textadept/interface.xpm b/editors/textadept/interface.xpm new file mode 100644 index 0000000..62131e2 --- /dev/null +++ b/editors/textadept/interface.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char * interface_xpm[] = { +"16 16 19 1", +" c None", +". c #CC7729", +"+ c #D47D2D", +"@ c #D58032", +"# c #F0F0F0", +"$ c #D58134", +"% c #FFFFFF", +"& c #F5F5F5", +"* c #D6853B", +"= c #FBFBFB", +"- c #FDFDFD", +"; c #D58236", +"> c #F7F7F7", +", c #F2F2F2", +"' c #ECECEC", +") c #CF792A", +"! c #E7E7E7", +"~ c #CA7629", +"{ c #C37228", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@######@@@ ", +" $$$%&&&&&$$$ ", +" *****==***** ", +" *****--***** ", +" ;;;;;>>;;;;; ", +" @@@@@,,@@@@@ ", +" +++''''''+++ ", +" )))!!!!!!))) ", +" ~~~~~~~~~~~~ ", +" {{{{{{{{{{ ", +" ", +" "}; diff --git a/editors/textadept/keyword.xpm b/editors/textadept/keyword.xpm new file mode 100755 index 0000000..8c69f7e --- /dev/null +++ b/editors/textadept/keyword.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char * keyword_xpm[] = { +"16 16 24 1", +" c None", +". c #B91C1C", +"+ c #BA1C1C", +"@ c #BE1D1D", +"# c #C31E1E", +"$ c #C21E1E", +"% c #F0F0F0", +"& c #C71E1E", +"* c #F5F5F5", +"= c #CC1F1F", +"- c #FBFBFB", +"; c #CB1F1F", +"> c #CD1F1F", +", c #FDFDFD", +"' c #C91F1F", +") c #F7F7F7", +"! c #C41E1E", +"~ c #F2F2F2", +"{ c #C01D1D", +"] c #ECECEC", +"^ c #BB1D1D", +"/ c #E7E7E7", +"( c #B71C1C", +"_ c #B21B1B", +" ", +" ", +" ......+... ", +" @@@@@@@@@@@@ ", +" #$%%%%%%$$#$ ", +" &&*******&&& ", +" ==--==;---== ", +" >>,,>>>>,,>> ", +" ''))''''))'' ", +" !!~~!!!~~~!! ", +" {{]]]]]]]{{{ ", +" ^^//////^^^^ ", +" (((((((((((( ", +" __________ ", +" ", +" "}; diff --git a/editors/textadept/module.xpm b/editors/textadept/module.xpm new file mode 100755 index 0000000..d7006e9 --- /dev/null +++ b/editors/textadept/module.xpm @@ -0,0 +1,33 @@ +/* XPM */ +static char * module_xpm[] = { +"16 16 14 1", +" c None", +". c #000000", +"+ c #000100", +"@ c #FFFF83", +"# c #FFFF00", +"$ c #FFFF28", +"% c #FFFF6A", +"& c #FFFF4C", +"* c #D5D500", +"= c #CDCD00", +"- c #A3A300", +"; c #B2B200", +"> c #C3C300", +", c #919100", +" ", +" .+ ", +" .@#+ ", +" .@#+ ", +" .$@##+ ", +" ..%@##++ ", +" ..&%%@####++ ", +" .@@@@@%######+ ", +" +*****=-;;;;;+ ", +" ++>==*;--,.. ", +" ++=*;-.. ", +" +>*;,. ", +" +*;. ", +" +*;. ", +" ++ ", +" "}; diff --git a/editors/textadept/modules/dmd/dcd.lua b/editors/textadept/modules/dmd/dcd.lua new file mode 100644 index 0000000..6bf6cf5 --- /dev/null +++ b/editors/textadept/modules/dmd/dcd.lua @@ -0,0 +1,491 @@ +local M = {} + +M.PATH_TO_DCD_CLIENT = "dcd-client" + +function M.registerImages() + buffer:register_image(1, M.FIELD) + buffer:register_image(2, M.FUNCTION) + buffer:register_image(3, M.PACKAGE) + buffer:register_image(4, M.MODULE) + buffer:register_image(5, M.KEYWORD) + buffer:register_image(6, M.CLASS) + buffer:register_image(7, M.UNION) + buffer:register_image(8, M.STRUCT) + buffer:register_image(9, M.INTERFACE) + buffer:register_image(10, M.ENUM) +end + +local function showCompletionList(r) + M.registerImages() + local setting = buffer.auto_c_choose_single + buffer.auto_c_choose_single = false; + buffer.auto_c_max_width = 0 + local completions = {} + for symbol, kind in r:gmatch("([@%w_%p]+)\t(%a)\n") do + completion = symbol + if kind == "k" then + completion = completion .. "?5" + elseif kind == "v" then + completion = completion .. "?1" + elseif kind == "e" then + completion = completion .. "?10" + elseif kind == "s" then + completion = completion .. "?8" + elseif kind == "g" then + completion = completion .. "?10" + elseif kind == "u" then + completion = completion .. "?7" + elseif kind == "m" then + completion = completion .. "?1" + elseif kind == "c" then + completion = completion .. "?6" + elseif kind == "i" then + completion = completion .. "?9" + elseif kind == "f" then + completion = completion .. "?2" + elseif kind == "M" then + completion = completion .. "?4" + elseif kind == "P" then + completion = completion .. "?3" + end + completions[#completions + 1] = completion + end + table.sort(completions, function(a, b) return string.upper(a) < string.upper(b) end) + buffer:auto_c_show(0, table.concat(completions, " ")) + buffer.auto_c_choose_single = setting +end + +local function showCalltips(calltip) + for tip in calltip:gmatch("(.-)\n") do + buffer:call_tip_show(buffer.current_pos, tip) + break + end +end + +function M.autocomplete(ch) + if buffer:get_lexer() ~= "dmd" then return end + if ch > 255 then return end + local character = string.char(ch) + if character == "." or character == "(" then + local fileName = os.tmpname() + local tmpFile = io.open(fileName, "w") + tmpFile:write(buffer:get_text()) + local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos + .. " " .. fileName + print(command) + local p = io.popen(command) + local r = p:read("*a") + print(r) + if r ~= "\n" then + if character == "." then + showCompletionList(r) + else + showCalltips(r) + end + end + os.remove(fileName) + end +end + +-- union icon +M.UNION = [[ +/* XPM */ +static char * union_xpm[] = { +"16 16 18 1", +" c None", +". c #A06B35", +"+ c #A87038", +"@ c #AC7339", +"# c #F7EFE7", +"$ c #AF753A", +"% c #F9F4EE", +"& c #B3783C", +"* c #FCFAF7", +"= c #FDFBF8", +"- c #B1763B", +"; c #FAF5F0", +"> c #F8F1EA", +", c #A97138", +"' c #F4EBE1", +") c #A36D36", +"! c #F2E6D9", +"~ c #9C6833", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@##@@@@##@@ ", +" $$%%$$$$%%$$ ", +" &&**&&&&**&& ", +" &&==&&&&==&& ", +" --;;----;;-- ", +" @@>>@@@@>>@@ ", +" ,,'''''''',, ", +" )))!!!!!!))) ", +" ............ ", +" ~~~~~~~~~~ ", +" ", +" "}; +]] + +-- class icon +M.CLASS = [[ +/* XPM */ +static char * class_xpm[] = { +"16 16 18 1", +" c None", +". c #006AD6", +"+ c #006DDC", +"@ c #0070E2", +"# c #F0F0F0", +"$ c #0072E6", +"% c #F5F5F5", +"& c #0075EC", +"* c #FBFBFB", +"= c #F7F7F7", +"- c #0073E8", +"; c #F2F2F2", +"> c #006EDE", +", c #ECECEC", +"' c #006BD8", +") c #E7E7E7", +"! c #0069D4", +"~ c #0066CE", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@@#####@@@ ", +" $$$%%%%%%%$$ ", +" &&***&&&**&& ", +" &&==&&&&&&&& ", +" --==-------- ", +" @@;;;@@@;;@@ ", +" >>>,,,,,,,>> ", +" '''')))))''' ", +" !!!!!!!!!!!! ", +" ~~~~~~~~~~ ", +" ", +" "}; +]] + + +-- interface icon +M.INTERFACE = [[ +/* XPM */ +static char * interface_xpm[] = { +"16 16 19 1", +" c None", +". c #CC7729", +"+ c #D47D2D", +"@ c #D58032", +"# c #F0F0F0", +"$ c #D58134", +"% c #FFFFFF", +"& c #F5F5F5", +"* c #D6853B", +"= c #FBFBFB", +"- c #FDFDFD", +"; c #D58236", +"> c #F7F7F7", +", c #F2F2F2", +"' c #ECECEC", +") c #CF792A", +"! c #E7E7E7", +"~ c #CA7629", +"{ c #C37228", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@######@@@ ", +" $$$%&&&&&$$$ ", +" *****==***** ", +" *****--***** ", +" ;;;;;>>;;;;; ", +" @@@@@,,@@@@@ ", +" +++''''''+++ ", +" )))!!!!!!))) ", +" ~~~~~~~~~~~~ ", +" {{{{{{{{{{ ", +" ", +" "}; +]] + +-- struct icon +M.STRUCT = [[ +/* XPM */ +static char * struct_xpm[] = { +"16 16 19 1", +" c None", +". c #000098", +"+ c #00009E", +"@ c #0000A2", +"# c #F0F0F0", +"$ c #0000A4", +"% c #F5F5F5", +"& c #FFFFFF", +"* c #0000A8", +"= c #FBFBFB", +"- c #FDFDFD", +"; c #0000A6", +"> c #F7F7F7", +", c #F2F2F2", +"' c #ECECEC", +") c #00009A", +"! c #E7E7E7", +"~ c #000096", +"{ c #000092", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@#######@@ ", +" $$%&%%%%%%$$ ", +" **===******* ", +" **-------*** ", +" ;;;>>>>>>>;; ", +" @@@@@@@,,,@@ ", +" ++''''''''++ ", +" ))!!!!!!!))) ", +" ~~~~~~~~~~~~ ", +" {{{{{{{{{{ ", +" ", +" "}; +]] + +-- functions icon +M.FUNCTION = [[ +/* XPM */ +static char * function_xpm[] = { +"16 16 17 1", +" c None", +". c #317025", +"+ c #367B28", +"@ c #387F2A", +"# c #F0F0F0", +"$ c #FFFFFF", +"% c #F5F5F5", +"& c #3A832C", +"* c #FBFBFB", +"= c #FDFDFD", +"- c #F7F7F7", +"; c #F2F2F2", +"> c #ECECEC", +", c #347627", +"' c #E7E7E7", +") c #306D24", +"! c #2F6A23", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@######@@@ ", +" @@@$%%%%%@@@ ", +" &&&**&&&&&&& ", +" &&&=====&&&& ", +" @@@-----@@@@ ", +" @@@;;@@@@@@@ ", +" +++>>+++++++ ", +" ,,,'',,,,,,, ", +" )))))))))))) ", +" !!!!!!!!!! ", +" ", +" "}; +]] + +-- fields icon +M.FIELD = [[ +/* XPM */ +static char * variable_xpm[] = { +"16 16 18 1", +" c None", +". c #933093", +"+ c #A035A0", +"@ c #A537A5", +"# c #FFFFFF", +"$ c #F0F0F0", +"% c #A637A6", +"& c #F5F5F5", +"* c #AC39AC", +"= c #FBFBFB", +"- c #FDFDFD", +"; c #F7F7F7", +"> c #F2F2F2", +", c #ECECEC", +"' c #9A339A", +") c #E7E7E7", +"! c #8E2F8E", +"~ c #8B2E8B", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@#$@@@@$$@@ ", +" %%&#%%%%&&%% ", +" **==****==** ", +" ***--**--*** ", +" %%%;;%%;;%%% ", +" @@@@>>>>@@@@ ", +" ++++,,,,++++ ", +" '''''))''''' ", +" !!!!!!!!!!!! ", +" ~~~~~~~~~~ ", +" ", +" "}; +]] + +--package icon +M.PACKAGE = [[ +/* XPM */ +static char * package_xpm[] = { +"16 16 6 1", +" c None", +". c #000100", +"+ c #050777", +"@ c #242BAE", +"# c #2E36BF", +"$ c #434FE5", +" ", +" ............ ", +" .$$$$$$$$$$$$. ", +" .$##@@+$##@@+. ", +" .$#@@@+$#@@@+. ", +" .$@@@#+$@@@#+. ", +" .$@@##+$@@##+. ", +" .$+++++$+++++. ", +" .$$$$$$$$$$$$. ", +" .$##@@+$##@@+. ", +" .$#@@@+$#@@@+. ", +" .$@@@#+$@@@#+. ", +" .$@@##+$@@##+. ", +" .$+++++$+++++. ", +" ............ ", +" "}; +]] + +-- module icon +M.MODULE = [[ +/* XPM */ +static char * module_xpm[] = { +"16 16 14 1", +" c None", +". c #000000", +"+ c #000100", +"@ c #FFFF83", +"# c #FFFF00", +"$ c #FFFF28", +"% c #FFFF6A", +"& c #FFFF4C", +"* c #D5D500", +"= c #CDCD00", +"- c #A3A300", +"; c #B2B200", +"> c #C3C300", +", c #919100", +" ", +" .+ ", +" .@#+ ", +" .@#+ ", +" .$@##+ ", +" ..%@##++ ", +" ..&%%@####++ ", +" .@@@@@%######+ ", +" +*****=-;;;;;+ ", +" ++>==*;--,.. ", +" ++=*;-.. ", +" +>*;,. ", +" +*;. ", +" +*;. ", +" ++ ", +" "}; +]] + +M.ENUM = [[ +/* XPM */ +static char * enum_dec_xpm[] = { +"16 16 18 1", +" c None", +". c #6D43C0", +"+ c #754EC3", +"@ c #7751C4", +"# c #F0F0F0", +"$ c #7852C5", +"% c #FFFFFF", +"& c #F5F5F5", +"* c #7D58C7", +"= c #FBFBFB", +"- c #FDFDFD", +"; c #F7F7F7", +"> c #F2F2F2", +", c #ECECEC", +"' c #7048C2", +") c #E7E7E7", +"! c #6A40BF", +"~ c #673EBA", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@######@@@ ", +" $$$%&&&&&$$$ ", +" ***==******* ", +" ***-----**** ", +" $$$;;;;;$$$$ ", +" @@@>>@@@@@@@ ", +" +++,,,,,,+++ ", +" '''))))))''' ", +" !!!!!!!!!!!! ", +" ~~~~~~~~~~ ", +" ", +" "}; +]] + +-- keyword icon +M.KEYWORD = [[ +/* XPM */ +static char * keyword_xpm[] = { +"16 16 24 1", +" c None", +". c #B91C1C", +"+ c #BA1C1C", +"@ c #BE1D1D", +"# c #C31E1E", +"$ c #C21E1E", +"% c #F0F0F0", +"& c #C71E1E", +"* c #F5F5F5", +"= c #CC1F1F", +"- c #FBFBFB", +"; c #CB1F1F", +"> c #CD1F1F", +", c #FDFDFD", +"' c #C91F1F", +") c #F7F7F7", +"! c #C41E1E", +"~ c #F2F2F2", +"{ c #C01D1D", +"q c #ECECEC", +"^ c #BB1D1D", +"/ c #E7E7E7", +"( c #B71C1C", +"_ c #B21B1B", +" ", +" ", +" .......... ", +" @@@@@@@@@@@@ ", +" #$%%%%%%$$#$ ", +" &&*******&&& ", +" ==--==;---== ", +" >>,,>>>>,,>> ", +" ''))''''))'' ", +" !!~~!!!~~~!! ", +" {{qqqqqqq{{{ ", +" ^^//////^^^^ ", +" (((((((((((( ", +" __________ ", +" ", +" "}; +]] + +return M diff --git a/editors/textadept/package.xpm b/editors/textadept/package.xpm new file mode 100755 index 0000000..57a1fe9 --- /dev/null +++ b/editors/textadept/package.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char * package_xpm[] = { +"16 16 6 1", +" c None", +". c #000100", +"+ c #050777", +"@ c #242BAE", +"# c #2E36BF", +"$ c #434FE5", +" ", +" ............ ", +" .$$$$$$$$$$$$. ", +" .$##@@+$##@@+. ", +" .$#@@@+$#@@@+. ", +" .$@@@#+$@@@#+. ", +" .$@@##+$@@##+. ", +" .$+++++$+++++. ", +" .$$$$$$$$$$$$. ", +" .$##@@+$##@@+. ", +" .$#@@@+$#@@@+. ", +" .$@@@#+$@@@#+. ", +" .$@@##+$@@##+. ", +" .$+++++$+++++. ", +" ............ ", +" "}; diff --git a/editors/textadept/struct.xpm b/editors/textadept/struct.xpm new file mode 100644 index 0000000..9773782 --- /dev/null +++ b/editors/textadept/struct.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char * struct_xpm[] = { +"16 16 19 1", +" c None", +". c #000098", +"+ c #00009E", +"@ c #0000A2", +"# c #F0F0F0", +"$ c #0000A4", +"% c #F5F5F5", +"& c #FFFFFF", +"* c #0000A8", +"= c #FBFBFB", +"- c #FDFDFD", +"; c #0000A6", +"> c #F7F7F7", +", c #F2F2F2", +"' c #ECECEC", +") c #00009A", +"! c #E7E7E7", +"~ c #000096", +"{ c #000092", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@#######@@ ", +" $$%&%%%%%%$$ ", +" **===******* ", +" **-------*** ", +" ;;;>>>>>>>;; ", +" @@@@@@@,,,@@ ", +" ++''''''''++ ", +" ))!!!!!!!))) ", +" ~~~~~~~~~~~~ ", +" {{{{{{{{{{ ", +" ", +" "}; diff --git a/editors/textadept/union.xpm b/editors/textadept/union.xpm new file mode 100644 index 0000000..6b96da1 --- /dev/null +++ b/editors/textadept/union.xpm @@ -0,0 +1,37 @@ +/* XPM */ +static char * union_xpm[] = { +"16 16 18 1", +" c None", +". c #A06B35", +"+ c #A87038", +"@ c #AC7339", +"# c #F7EFE7", +"$ c #AF753A", +"% c #F9F4EE", +"& c #B3783C", +"* c #FCFAF7", +"= c #FDFBF8", +"- c #B1763B", +"; c #FAF5F0", +"> c #F8F1EA", +", c #A97138", +"' c #F4EBE1", +") c #A36D36", +"! c #F2E6D9", +"~ c #9C6833", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@##@@@@##@@ ", +" $$%%$$$$%%$$ ", +" &&**&&&&**&& ", +" &&==&&&&==&& ", +" --;;----;;-- ", +" @@>>@@@@>>@@ ", +" ,,'''''''',, ", +" )))!!!!!!))) ", +" ............ ", +" ~~~~~~~~~~ ", +" ", +" "}; diff --git a/editors/textadept/variable.xpm b/editors/textadept/variable.xpm new file mode 100644 index 0000000..8555310 --- /dev/null +++ b/editors/textadept/variable.xpm @@ -0,0 +1,37 @@ +/* XPM */ +static char * variable_xpm[] = { +"16 16 18 1", +" c None", +". c #933093", +"+ c #A035A0", +"@ c #A537A5", +"# c #FFFFFF", +"$ c #F0F0F0", +"% c #A637A6", +"& c #F5F5F5", +"* c #AC39AC", +"= c #FBFBFB", +"- c #FDFDFD", +"; c #F7F7F7", +"> c #F2F2F2", +", c #ECECEC", +"' c #9A339A", +") c #E7E7E7", +"! c #8E2F8E", +"~ c #8B2E8B", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@#$@@@@$$@@ ", +" %%&#%%%%&&%% ", +" **==****==** ", +" ***--**--*** ", +" %%%;;%%;;%%% ", +" @@@@>>>>@@@@ ", +" ++++,,,,++++ ", +" '''''))''''' ", +" !!!!!!!!!!!! ", +" ~~~~~~~~~~ ", +" ", +" "}; diff --git a/editors/vim/README.md b/editors/vim/README.md new file mode 100644 index 0000000..106acc3 --- /dev/null +++ b/editors/vim/README.md @@ -0,0 +1 @@ +#VIM Integration diff --git a/modulecache.d b/modulecache.d index 6dd6987..a4c9280 100644 --- a/modulecache.d +++ b/modulecache.d @@ -66,6 +66,7 @@ struct ModuleCache */ static ACSymbol[] getSymbolsInModule(string moduleName) { + writeln("Getting symbols for module", moduleName); string location = resolveImportLoctation(moduleName); if (location is null) return []; @@ -81,6 +82,7 @@ struct ModuleCache Module mod = parseModule(tokens, location, &doesNothing); auto visitor = new AutocompleteVisitor; visitor.visit(mod); + visitor.scope_.resolveSymbolTypes(); SysTime access; SysTime modification; getTimes(location, access, modification); diff --git a/server.d b/server.d index f0a4ae7..ce0be93 100644 --- a/server.d +++ b/server.d @@ -56,7 +56,7 @@ int main(string[] args) foreach (path; importPaths) ModuleCache.addImportPath(path); - writeln(ModuleCache.getImportPaths()); + writeln("Import directories: ", ModuleCache.getImportPaths()); auto socket = new TcpSocket(AddressFamily.INET); socket.blocking = true; @@ -72,7 +72,11 @@ int main(string[] args) { auto s = socket.accept(); s.blocking = true; - scope (exit) s.close(); + scope (exit) + { + s.shutdown(SocketShutdown.BOTH); + s.close(); + } ptrdiff_t bytesReceived = s.receive(buffer); size_t messageLength; // bit magic! @@ -102,6 +106,7 @@ int main(string[] args) } else if (request.kind == RequestKind.clearCache) { + writeln("Clearing cache."); ModuleCache.clear(); } else if (request.kind == RequestKind.shutdown)