diff --git a/.gitmodules b/.gitmodules index f8aa23d..fac66e6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "msgpack-d"] path = msgpack-d url = https://github.com/msgpack/msgpack-d.git -[submodule "dscanner"] - path = dscanner - url = https://github.com/Hackerpilot/Dscanner.git [submodule "editors/ktexteditor"] path = editors/ktexteditor url = https://github.com/Dav1dde/lumen.git @@ -13,3 +10,7 @@ [submodule "containers"] path = containers url = https://github.com/economicmodeling/containers.git +[submodule "libdparse"] + path = libdparse + url = https://github.com/Hackerpilot/libdparse.git + branch = master diff --git a/autocomplete.d b/autocomplete.d index 12eab8f..c91968f 100644 --- a/autocomplete.d +++ b/autocomplete.d @@ -205,8 +205,7 @@ auto getTokensBeforeCursor(const(ubyte[]) sourceCode, size_t cursorPosition, { LexerConfig config; config.fileName = "stdin"; - auto tokens = byToken(cast(ubyte[]) sourceCode, config, cache); - tokenArray = tokens.array(); + tokenArray = getTokensForParser(cast(ubyte[]) sourceCode, config, cache); auto sortedTokens = assumeSorted(tokenArray); return sortedTokens.lowerBound(cast(size_t) cursorPosition); } diff --git a/build.bat b/build.bat index 9c7bab1..8913129 100644 --- a/build.bat +++ b/build.bat @@ -1,3 +1,3 @@ -dmd -wi client.d messages.d stupidlog.d msgpack-d/src/msgpack.d -Imsgpack-d/src -release -inline -O -ofdcd-client +dmd -wi client.d messages.d stupidlog.d msgpack-d/src/msgpack.d -Imsgpack-d/src -release -inline -O -ofdcd-client -L/EXETYPE:NT -L/SUBSYSTEM:WINDOWS dmd actypes.d conversion/astconverter.d conversion/first.d conversion/second.d conversion/third.d autocomplete.d constants.d messages.d modulecache.d semantic.d server.d stupidlog.d string_interning.d dscanner/std/d/ast.d dscanner/std/d/entities.d dscanner/std/d/lexer.d dscanner/std/d/parser.d dscanner/std/lexer.d dscanner/std/allocator.d dscanner/formatter.d containers/src/memory/appender.d containers/src/memory/allocators.d containers/src/containers/dynamicarray.d containers/src/containers/ttree.d containers/src/containers/hashset.d containers/src/containers/unrolledlist.d containers/src/containers/internal/hash.d msgpack-d/src/msgpack.d -Icontainers/src -Imsgpack-d/src -Idscanner -wi -g -O -release -ofdcd-server diff --git a/build.sh b/build.sh index 31095cd..d80d54d 100755 --- a/build.sh +++ b/build.sh @@ -23,13 +23,13 @@ dmd\ server.d\ stupidlog.d\ string_interning.d\ - dscanner/std/d/ast.d\ - dscanner/std/d/entities.d\ - dscanner/std/d/lexer.d\ - dscanner/std/d/parser.d\ - dscanner/std/lexer.d\ - dscanner/std/allocator.d\ - dscanner/formatter.d\ + libdparse/src/std/d/ast.d\ + libdparse/src/std/d/entities.d\ + libdparse/src/std/d/lexer.d\ + libdparse/src/std/d/parser.d\ + libdparse/src/std/lexer.d\ + libdparse/src/std/allocator.d\ + libdparse/src/std/d/formatter.d\ containers/src/memory/allocators.d\ containers/src/memory/appender.d\ containers/src/containers/dynamicarray.d\ diff --git a/containers b/containers index 36a00d9..2a72525 160000 --- a/containers +++ b/containers @@ -1 +1 @@ -Subproject commit 36a00d9f109fde9c53db3173fae39439b007c0ce +Subproject commit 2a72525f649850f452f21e7f362f70440f487a61 diff --git a/conversion/astconverter.d b/conversion/astconverter.d index 67657fb..ac17f56 100644 --- a/conversion/astconverter.d +++ b/conversion/astconverter.d @@ -63,7 +63,8 @@ class SimpleParser : Parser override Unittest parseUnittest() { expect(tok!"unittest"); - skipBraces(); + if (currentIs(tok!"{")) + skipBraces(); return null; } diff --git a/conversion/first.d b/conversion/first.d index 6e107f7..b4411d8 100644 --- a/conversion/first.d +++ b/conversion/first.d @@ -19,7 +19,7 @@ module conversion.first; import actypes; -import formatter; +import std.d.formatter; import std.allocator; import memory.allocators; import memory.appender; diff --git a/conversion/third.d b/conversion/third.d index 9d34561..5a832e2 100644 --- a/conversion/third.d +++ b/conversion/third.d @@ -190,7 +190,7 @@ private: ACSymbol* processSuffix(ACSymbol* symbol, const TypeSuffix suffix) { - import formatter; + import std.d.formatter; if (suffix.star) return symbol; if (suffix.array || suffix.type) diff --git a/dscanner b/dscanner deleted file mode 160000 index f54f782..0000000 --- a/dscanner +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f54f7823dc62c14b7afb6b7db6e7693e79be34fa diff --git a/editors/emacs/README.md b/editors/emacs/README.md index 780920b..2cf9285 100644 --- a/editors/emacs/README.md +++ b/editors/emacs/README.md @@ -1,16 +1,44 @@ -#EMACS Integration - -This is a first cut at emacs support. It is far from complete. +#Emacs Integration ##Requirements -* You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package -* This integration will not automatically start dcd-server, so you'll have to do that yourself. -* Make sure dcd-client is in your path -* Add the following to your .emacs +* You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package. +[yasnippet](https://github.com/capitaomorte/yasnippet) and [popwin](https://github.com/m2ym/popwin-el) is recommended. +* Make sure dcd-client and dcd-server is in your exec-path. Otherwise, please set the variable ```dcd-exectutable``` and ```dcd-server-executable``` using ```M-x customize```. - (require 'ac-dcd) - (add-to-list 'ac-modes 'd-mode) - (defun ac-d-mode-setup () - (setq ac-sources (append '(ac-source-dcd) ac-sources)) - (global-auto-complete-mode t)) - (add-hook 'd-mode-hook 'ac-d-mode-setup) +## Setup +* First, follow the Setup section in the root README. +* Second, add the following to your .emacs. With this setting, dcd-server starts automatically when you open file in d-mode. (Of course, you should edit ```path_to_ac-dcd.el``` to suit your enviroment.) + +``` +;;; ac-dcd +(add-to-list 'load-path "path_to_ac-dcd.el") +(require 'ac-dcd) +(add-to-list 'ac-modes 'd-mode) + +(add-hook 'd-mode-hook + '(lambda () "set up ac-dcd" + (ac-dcd-maybe-start-server) + (add-to-list 'ac-sources 'ac-source-dcd))) + +(define-key d-mode-map (kbd "C-c ?") 'ac-dcd-show-ddoc-with-buffer) +(define-key d-mode-map (kbd "C-c .") 'ac-dcd-goto-definition) +(define-key d-mode-map (kbd "C-c ,") 'ac-dcd-goto-def-pop-marker) + +(when (featurep 'popwin) +(add-to-list 'popwin:special-display-config +`(,ac-dcd-document-buffer-name :position right :width 80))) +``` + +* Third, set import path using ```M-x customize-variable RET ac-dcd-flags```. +* When something is wrong, please check variables with ```M-x customize-apropos RET ac-dcd``` and restart server with ```M-x ac-dcd-init-server```. + +## Features +* Dlang source for auto-complete +* Function calltip expansion with yasnippet +* Show ddoc with ```C-c ?``` +* Goto definition with ```C-c .``` +* After goto definition, you can pop to previous position with ```C-c ,``` + +## TODO +* Better error handling +* Multi byte character support (Need help!) diff --git a/editors/emacs/ac-dcd.el b/editors/emacs/ac-dcd.el index 3c4f121..6816a3f 100644 --- a/editors/emacs/ac-dcd.el +++ b/editors/emacs/ac-dcd.el @@ -21,54 +21,110 @@ ;;; Code: -(provide 'ac-dcd) (require 'auto-complete) - +(require 'rx) +(require 'yasnippet) +(require 'eshell) (defcustom ac-dcd-executable - (executable-find "dcd-client") - "*Location of dcd-client executable" + "dcd-client" + "Location of dcd-client executable." :group 'auto-complete :type 'file) -;;; Extra compilation flags to pass to dcd. (defcustom ac-dcd-flags nil - "Extra flags to pass to the Dcd executable. -This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \"-I.\" )." + "Extra flags to pass to the dcd-server. +This variable will typically contain include paths, +e.g., (\"-I~/MyProject\", \"-I.\"). +You can't put port number flag here. Set `ac-dcd-server-port' instead." :group 'auto-complete :type '(repeat (string :tag "Argument" ""))) (defconst ac-dcd-completion-pattern - "^\\(%s[^\s\n]*\\)[ \t]+[cisuvmkfgepM]") + "^\\(%s[^\s\n]*\\)[ \t]+\\([cisuvmkfgepM]\\)" + "Regex to parse dcd output. +\\1 is candidate itself, \\2 is kind of candidate.") -(defconst ac-dcd-error-buffer-name "*dcd error*") +(defconst ac-dcd-error-buffer-name "*dcd-error*") +(defconst ac-dcd-output-buffer-name "*dcd-output*") +(defconst ac-dcd-document-buffer-name "*dcd-document*") +(defcustom ac-dcd-server-executable + "dcd-server" + "Location of dcd-server executable." + :group 'auto-complete + :type 'file) + +(defcustom ac-dcd-server-port 9166 + "Port number of dcd-server. default is 9166." + :group 'auto-complete) + +(defvar ac-dcd-delay-after-kill-process 200 + "Duration after killing server process in milli second. +If `ac-dcd-init-server' doesn't work correctly, please set bigger number for this variable.") + + +;;server handle functions + +(defun ac-dcd-stop-server () + "Stop dcd-server manually. Ordinary, you don't have to call it. +If you want to restart server, use `ac-dcd-init-server' instead." + (interactive) + (interrupt-process "dcd-server")) + +(defsubst ac-dcd-start-server () + "Start dcd-server." + (let ((buf (get-buffer-create "*dcd-server*"))) + (with-current-buffer buf (start-process "dcd-server" (current-buffer) + ac-dcd-server-executable + (mapconcat 'identity ac-dcd-flags " ") + "-p" + (format "%s" ac-dcd-server-port) + )))) + +(defun ac-dcd-maybe-start-server () + "Start dcd-server. When the server process is already running, do nothing." + (unless (get-process "dcd-server") + (ac-dcd-start-server))) + +(defun ac-dcd-init-server () + "Start dcd-server. When the server process is already running, restart it." + (interactive) + (when (get-process "dcd-server") + (ac-dcd-stop-server) + (sleep-for 0 ac-dcd-delay-after-kill-process)) + (ac-dcd-start-server)) + + +;; output parser functions (defun ac-dcd-parse-output (prefix) + "Parse dcd output." (goto-char (point-min)) (let ((pattern (format ac-dcd-completion-pattern (regexp-quote prefix))) - lines match detailed_info + lines match detailed-info (prev-match "")) (while (re-search-forward pattern nil t) (setq match (match-string-no-properties 1)) (unless (string= "Pattern" match) - (setq detailed_info (match-string-no-properties 2)) + (setq detailed-info (match-string-no-properties 2)) (if (string= match prev-match) (progn - (when detailed_info + (when detailed-info (setq match (propertize match 'ac-dcd-help (concat (get-text-property 0 'ac-dcd-help (car lines)) "\n" - detailed_info))) + detailed-info))) (setf (car lines) match))) (setq prev-match match) - (when detailed_info - (setq match (propertize match 'ac-dcd-help detailed_info))) + (when detailed-info + (setq match (propertize match 'ac-dcd-help detailed-info))) (push match lines)))) lines)) (defun ac-dcd-handle-error (res args) + "Notify error on parse failure." (goto-char (point-min)) (let* ((buf (get-buffer-create ac-dcd-error-buffer-name)) (cmd (concat ac-dcd-executable " " (mapconcat 'identity args " "))) @@ -89,72 +145,51 @@ This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \ (setq buffer-read-only t) (goto-char (point-min)))))) -(defun ac-dcd-call-process (prefix &rest args) - (let ((buf (get-buffer-create "*dcd-output*")) + +;; utility functions to call process + +(defun ac-dcd-call-process (prefix args) + (let ((buf (get-buffer-create ac-dcd-output-buffer-name)) res) (with-current-buffer buf (erase-buffer)) (setq res (apply 'call-process-region (point-min) (point-max) - ac-dcd-executable nil buf nil args)) + ac-dcd-executable nil buf nil + args + )) (with-current-buffer buf (unless (eq 0 res) (ac-dcd-handle-error res args)) ;; Still try to get any useful input. (ac-dcd-parse-output prefix)))) +(defsubst ac-dcd-cursor-position () + "Get cursor position to pass to dcd-client. +TODO: multi byte character support" + (point)) + (defsubst ac-dcd-build-complete-args (pos) - (append '() - '("-c") - (list (format "%s" pos)) - ac-dcd-flags)) + (list + "-c" + (format "%s" pos) + "-p" + (format "%s" ac-dcd-server-port) + )) -(defsubst ac-dcd-clean-document (s) - (when s - (setq s (replace-regexp-in-string "<#\\|#>\\|\\[#" "" s)) - (setq s (replace-regexp-in-string "#\\]" " " s))) - s) - -(defun ac-dcd-document (item) - (if (stringp item) - (let (s) - (setq s (get-text-property 0 'ac-dcd-help item)) - (ac-dcd-clean-document s)))) - (defsubst ac-in-string/comment () "Return non-nil if point is in a literal (a comment or string)." (nth 8 (syntax-ppss))) + +;; interface to communicate with auto-complete.el + (defun ac-dcd-candidate () (unless (ac-in-string/comment) (save-restriction (widen) - (apply 'ac-dcd-call-process - ac-prefix - (ac-dcd-build-complete-args (point)))))) - -(defvar ac-template-start-point nil) -(defvar ac-template-candidates (list "ok" "no" "yes:)")) - -(defun ac-dcd-action () - (interactive) - (let ((help (ac-dcd-clean-document (get-text-property 0 'ac-dcd-help (cdr ac-last-completion)))) - (raw-help (get-text-property 0 'ac-dcd-help (cdr ac-last-completion))) - (candidates (list)) ss fn args (ret-t "") ret-f) - (setq ss (split-string raw-help "\n")) - (dolist (s ss) - (when (string-match "\\[#\\(.*\\)#\\]" s) - (setq ret-t (match-string 1 s))) - (setq s (replace-regexp-in-string "\\[#.*?#\\]" "" s))) - (cond (candidates - (setq candidates (delete-dups candidates)) - (setq candidates (nreverse candidates)) - (setq ac-template-candidates candidates) - (setq ac-template-start-point (point)) - (ac-complete-template) - (unless (cdr candidates) ;; unless length > 1 - (message (replace-regexp-in-string "\n" " ; " help)))) - (t - (message (replace-regexp-in-string "\n" " ; " help)))))) + (ac-dcd-call-process + ac-prefix + (ac-dcd-build-complete-args (ac-dcd-cursor-position)))))) (defun ac-dcd-prefix () (or (ac-prefix-symbol) @@ -166,64 +201,299 @@ This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \ (eq ?: (char-before (1- (point)))))) (point))))) +(defun ac-dcd-document (item) + "Return popup document of `ITEM'." + (if (stringp item) + (let (s) + (setq s (get-text-property 0 'ac-dcd-help item)) + (cond + ((equal s "c") "class") + ((equal s "i") "interface") + ((equal s "s") "struct") + ((equal s "u") "union") + ((equal s "v") "variable") + ((equal s "m") "member variable") + ((equal s "k") "keyword") + ((equal s "f") "function") + ((equal s "g") "enum") + ((equal s "e") "enum member") + ((equal s "P") "package") + ((equal s "M") "module") + ((equal s "a") "array") + ((equal s "A") "associative array") + ((equal s "l") "alias") + ((equal s "t") "template") + ((equal s "T") "mixin template") + (t (format "candidate kind undetected: %s" s)) + )))) + + +(defun ac-dcd-action () + "Try function calltip expansion." + (when (featurep 'yasnippet) + + (let ((lastcompl (cdr ac-last-completion))) + (cond + ((equal "f" (get-text-property 0 'ac-dcd-help lastcompl)) ; when it was a function + (progn + (ac-complete-dcd-calltips))) + (t nil) + )))) + (ac-define-source dcd '((candidates . ac-dcd-candidate) (prefix . ac-dcd-prefix) (requires . 0) (document . ac-dcd-document) - (action . ac-dcd-action) - (cache))) - -(defun ac-dcd-same-count-in-string (c1 c2 s) - (let ((count 0) (cur 0) (end (length s)) c) - (while (< cur end) - (setq c (aref s cur)) - (cond ((eq c1 c) - (setq count (1+ count))) - ((eq c2 c) - (setq count (1- count)))) - (setq cur (1+ cur))) - (= count 0))) - -(defun ac-dcd-split-args (s) - (let ((sl (split-string s ", *"))) - (cond ((string-match "<\\|(" s) - (let ((res (list)) (pre "") subs) - (while sl - (setq subs (pop sl)) - (unless (string= pre "") - (setq subs (concat pre ", " subs)) - (setq pre "")) - (cond ((and (ac-dcd-same-count-in-string ?\< ?\> subs) - (ac-dcd-same-count-in-string ?\( ?\) subs)) - (push subs res)) - (t - (setq pre subs)))) - (nreverse res))) - (t - sl)))) - -(defun ac-template-candidate () - ac-template-candidates) - -(defun ac-template-action () - (interactive) - (unless (null ac-template-start-point) - (let ((pos (point)) sl (snp "") - (s (get-text-property 0 'raw-args (cdr ac-last-completion))))))) - -(defun ac-template-prefix () - ac-template-start-point) - - -;; this source shall only be used internally. -(ac-define-source template - '((candidates . ac-template-candidate) - (prefix . ac-template-prefix) - (requires . 0) - (action . ac-template-action) - (document . ac-dcd-document) + (action . ac-dcd-action) (cache) - (symbol . "t"))) + (symbol . "D") + )) -;;; auto-complete-dcd.el ends here + +;; function calltip expansion with yasnippet + +(defun ac-dcd-calltip-candidate () + "Do calltip completion of the D symbol at point. +The cursor must be at the end of a D symbol. +When the symbol is not a function, returns nothing" + (let ((buf (get-buffer-create ac-dcd-output-buffer-name))) + (ac-dcd-call-process-for-calltips) + (with-current-buffer buf (ac-dcd-parse-calltips)) + )) + +(defun ac-dcd-call-process-for-calltips () + "Call process to get calltips of the function at point." + (insert "( ;") + (backward-char 2) + + (ac-dcd-call-process + (concat (cdr ac-last-completion) "(") + (ac-dcd-build-complete-args (ac-dcd-cursor-position))) + + (forward-char 2) + (delete-char -3) + + ) + + +(defconst ac-dcd-calltip-pattern + (rx bol (submatch (* nonl)) (submatch "(" (* nonl) ")") eol) + "Regexp to parse calltip completion output. +\\1 is function return type (if exists) and name, and \\2 is args.") + +(defsubst ac-dcd-cleanup-function-candidate (s) + "Remove return type of the head of the function. +`S' is candidate string." + (let (res) + (with-temp-buffer + (insert s) + + ;;goto beggining of function name + (progn + (end-of-line) + (backward-sexp) + (re-search-backward (rx (or bol " ")))) + + (setq res (buffer-substring + (point) + (progn + (end-of-line) + (point)))) + (when (equal " " (substring res 0 1)) + (setq res (substring res 1))) + res + ))) + +(defun ac-dcd-parse-calltips () + "Parse dcd output for calltip completion. +It returns a list of calltip candidates." + (goto-char (point-min)) + (let ((pattern ac-dcd-calltip-pattern) + lines + match + (prev-match "")) + (while (re-search-forward pattern nil t) + (setq match + (ac-dcd-cleanup-function-candidate + (concat (match-string-no-properties 1) (match-string-no-properties 2)) + )) + (push match lines)) + lines + )) + +(defun ac-dcd-calltip-action () + "Format the calltip to yasnippet style. +This function should be called at *dcd-output* buf." + (let (beg end) + (save-excursion + (setq end (point)) + (setq beg (progn + (backward-sexp) + (point) + )) + (kill-region beg end)) + (let ((str (car kill-ring)) + yasstr) + (setq kill-ring (cdr kill-ring)); clean up kill-ring + + ;;remove parenthesis + (setq str (substring str 1 (- (length str) 1))) + + (setq yasstr + (mapconcat + (lambda (s) "format each args to yasnippet style" (concat "${" s "}")) + (split-string str ", ") + ", ")) + (setq yasstr (concat "(" yasstr ")")) + ;; ;;debug + ;; (message (format "str: %s" str)) + ;; (message (format "yasstr: %s" yasstr)) + (yas-expand-snippet yasstr) + ))) + +(defun ac-dcd-calltip-prefix () + (car ac-last-completion)) + +(ac-define-source dcd-calltips + '((candidates . ac-dcd-calltip-candidate) + (prefix . ac-dcd-calltip-prefix) + (action . ac-dcd-calltip-action) + (cache) + )) + + +;;show document + +(defun ac-dcd-reformat-document () + "Currently, it just decodes \n and \\n." + (with-current-buffer (get-buffer ac-dcd-document-buffer-name) + + ;;doit twice to catch '\n\n' + (goto-char (point-min)) + (while (re-search-forward (rx (and (not (any "\\")) (submatch "\\n"))) nil t) + (replace-match "\n" nil nil nil 1)) + + (goto-char (point-min)) + (while (re-search-forward (rx (and (not (any "\\")) (submatch "\\n"))) nil t) + (replace-match "\n" nil nil nil 1)) + + ;; replace '\\n' in D src to '\n' + (while (re-search-forward (rx "\\\\n") nil t) + (replace-match "\\\\n")) + )) + +(defun ac-dcd-get-ddoc (pos) + "Get document with `dcd-client --doc'. `POS' is cursor position." + (save-buffer) + (let ((args + (append + (ac-dcd-build-complete-args (ac-dcd-cursor-position)) + '("-d") + (list (buffer-file-name)))) + (buf (get-buffer-create ac-dcd-document-buffer-name))) + + ;; If I use `call-process', dcd-client errors out when to get long doc(e.g. doc of writef). + ;; I have no idea why. + (with-current-buffer buf + (erase-buffer) + (eshell-command + (mapconcat 'identity `(,(executable-find ac-dcd-executable) ,@args) " ") + t) + (when (or + (string= (buffer-string) "") + (string= (buffer-string) "\n\n\n") ;when symbol has no doc + ) + (error "No document for the symbol at point!")) + (buffer-string) + ))) + +(defun ac-dcd-show-ddoc-with-buffer () + "Display Ddoc at point using `display-buffer'." + (interactive) + (ac-dcd-get-ddoc (ac-dcd-cursor-position)) + (ac-dcd-reformat-document) + (display-buffer (get-buffer-create ac-dcd-document-buffer-name))) + + +;; goto definition +;; thanks to jedi.el by Takafumi Arakaki + +(defcustom ac-dcd-goto-definition-marker-ring-length 16 + "Length of marker ring to store `ac-dcd-goto-definition' call positions." + :group 'auto-complete) + +(defvar ac-dcd-goto-definition-marker-ring + (make-ring ac-dcd-goto-definition-marker-ring-length) + "Ring that stores ac-dcd-goto-symbol-declaration.") + +(defsubst ac-dcd-goto-def-push-marker () + "Push marker at point to goto-def ring." + (ring-insert ac-dcd-goto-definition-marker-ring (point-marker))) + +(defun ac-dcd-goto-def-pop-marker () + "Goto the point where `ac-dcd-goto-definition' was last called." + (interactive) + (if (ring-empty-p ac-dcd-goto-definition-marker-ring) + (error "Marker ring is empty. Can't pop.") + (let ((marker (ring-remove ac-dcd-goto-definition-marker-ring 0))) + (switch-to-buffer (or (marker-buffer marker) + (error "Buffer has been deleted"))) + (goto-char (marker-position marker)) + ;; Cleanup the marker so as to avoid them piling up. + (set-marker marker nil nil)))) + +(defun ac-dcd-goto-definition () + "Goto declaration of symbol at point." + (interactive) + (save-buffer) + (ac-dcd-call-process-for-symbol-declaration (point)) + (let* ((data (ac-dcd-parse-output-for-get-symbol-declaration)) + (file (car data)) + (offset (cdr data))) + (if (equal data '(nil . nil)) + (message "Not found") + (progn + (ac-dcd-goto-def-push-marker) + (if (string= file "stdin") ; When the declaration is in the current file + (progn + (goto-char (point-min)) + (forward-char (string-to-number offset))) + (progn + (find-file file) + (goto-char (point-min)) + (forward-char (string-to-number offset)))))))) + +;; utilities for goto-definition + +(defun ac-dcd-call-process-for-symbol-declaration (pos) + "Get location of symbol declaration with `dcd-client --symbolLocation'. +`POS' is cursor position." + (let ((args + (append + (ac-dcd-build-complete-args (ac-dcd-cursor-position)) + '("-l") + (list (buffer-file-name)))) + (buf (get-buffer-create ac-dcd-output-buffer-name))) + (with-current-buffer + buf (erase-buffer) + (apply 'call-process ac-dcd-executable nil buf nil args)) + (let ((output (with-current-buffer buf (buffer-string)))) + output))) + +(defun ac-dcd-parse-output-for-get-symbol-declaration () + "Parse output of `ac-dcd-get-symbol-declaration'. +output is just like following.\n +`(cons \"PATH_TO_IMPORT/import/std/stdio.d\" \"63946\")'" + (let ((buf (get-buffer-create ac-dcd-output-buffer-name))) + (with-current-buffer buf + (goto-char (point-min)) + (if (not (string= "Not found\n" (buffer-string))) + (progn (re-search-forward (rx (submatch (* nonl)) "\t" (submatch (* nonl)) "\n")) + (cons (match-string 1) (match-string 2))) + (cons nil nil))) + )) + + +(provide 'ac-dcd) +;;; ac-dcd.el ends here diff --git a/editors/textadept/modules/dmd/init.lua b/editors/textadept/modules/dmd/init.lua index 9595bc0..1ea3ea7 100644 --- a/editors/textadept/modules/dmd/init.lua +++ b/editors/textadept/modules/dmd/init.lua @@ -20,7 +20,7 @@ local function autocomplete() dcd.registerImages() dcd.autocomplete() if not buffer:auto_c_active() then - textadept.editing.autocomplete_word(keywords) + textadept.editing.autocomplete("word") end end diff --git a/libdparse b/libdparse new file mode 160000 index 0000000..d9387eb --- /dev/null +++ b/libdparse @@ -0,0 +1 @@ +Subproject commit d9387eb3b275295cd0263bdc273c4b0b63f29f98 diff --git a/modulecache.d b/modulecache.d index d3ef1fb..5d13a84 100644 --- a/modulecache.d +++ b/modulecache.d @@ -135,9 +135,8 @@ struct ModuleCache ACSymbol*[] symbols; - try - { - import core.memory; +// try +// { import std.stdio; import std.typecons; File f = File(cachedLocation); @@ -150,12 +149,9 @@ struct ModuleCache config.fileName = cachedLocation; auto parseStringCache = StringCache(StringCache.defaultBucketCount); auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 64))); - DynamicArray!(Token, false) tokens; - auto tokenRange = byToken( + const(Token)[] tokens = getTokensForParser( (source.length >= 3 && source[0 .. 3] == "\xef\xbb\xbf"c) ? source[3 .. $] : source, config, &parseStringCache); - foreach (t; tokenRange) - tokens.insert(t); Mallocator.it.deallocate(source); Module m = parseModuleSimple(tokens[], cachedLocation, semanticAllocator); @@ -180,12 +176,12 @@ struct ModuleCache typeid(Scope).destroy(third.moduleScope); typeid(SemanticSymbol).destroy(third.rootSymbol); symbolsAllocated += first.symbolsAllocated; - } - catch (Exception ex) - { - Log.error("Couln't parse ", location, " due to exception: ", ex.msg); - return []; - } +// } +// catch (Exception ex) +// { +// Log.error("Couln't parse ", location, " due to exception: ", ex.msg); +// return []; +// } SysTime access; SysTime modification; getTimes(cachedLocation, access, modification);