From 0ff231bc39662bf12e095dc8c705b19d99d72f7b Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Tue, 3 Jun 2014 02:43:28 -0700 Subject: [PATCH 01/12] Don't pop up a command window on Windows --- build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 1af4592911aef8eb55acf4a82ef740888d85fc93 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Wed, 18 Jun 2014 21:20:31 +0900 Subject: [PATCH 02/12] server starts automatically, user can configure port number, and so on. --- editors/emacs/README.md | 36 +++++++++++------ editors/emacs/ac-dcd.el | 88 +++++++++++++++++++++++++++++++++-------- 2 files changed, 96 insertions(+), 28 deletions(-) diff --git a/editors/emacs/README.md b/editors/emacs/README.md index 780920b..c1bd556 100644 --- a/editors/emacs/README.md +++ b/editors/emacs/README.md @@ -1,16 +1,28 @@ #EMACS Integration -This is a first cut at emacs support. It is far from complete. - ##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. +* 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. + +(add-to-list 'load-path "path_to_ac-dcd.el") +(require 'ac-dcd) +(add-to-list 'ac-modes 'd-mode) +(defun ac-d-mode-setup () + (ac-dcd-maybe-start-server) + (add-to-list 'ac-sources 'ac-source-dcd) + (auto-complete-mode t)) +(add-hook 'd-mode-hook 'ac-d-mode-setup) + +* 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```. + +## TODO +* better error detection +* detailed ac-source symbol +* goto definition +* show doc +* and so on... \ No newline at end of file diff --git a/editors/emacs/ac-dcd.el b/editors/emacs/ac-dcd.el index 3c4f121..4addbb2 100644 --- a/editors/emacs/ac-dcd.el +++ b/editors/emacs/ac-dcd.el @@ -21,19 +21,19 @@ ;;; Code: -(provide 'ac-dcd) (require 'auto-complete) (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" ""))) @@ -42,6 +42,52 @@ This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \ (defconst ac-dcd-error-buffer-name "*dcd error*") +(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.") + + + +(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)) + + + (defun ac-dcd-parse-output (prefix) (goto-char (point-min)) (let ((pattern (format ac-dcd-completion-pattern @@ -89,12 +135,16 @@ 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) + + +(defun ac-dcd-call-process (prefix args) (let ((buf (get-buffer-create "*dcd-output*")) 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)) @@ -102,10 +152,12 @@ This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \ (ac-dcd-parse-output prefix)))) (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) @@ -128,9 +180,9 @@ This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \ (unless (ac-in-string/comment) (save-restriction (widen) - (apply 'ac-dcd-call-process - ac-prefix - (ac-dcd-build-complete-args (point)))))) + (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:)")) @@ -172,7 +224,8 @@ This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \ (requires . 0) (document . ac-dcd-document) (action . ac-dcd-action) - (cache))) + (cache) + (symbol . "D"))) (defun ac-dcd-same-count-in-string (c1 c2 s) (let ((count 0) (cur 0) (end (length s)) c) @@ -203,6 +256,8 @@ This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \ (t sl)))) + + (defun ac-template-candidate () ac-template-candidates) @@ -226,4 +281,5 @@ This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \ (cache) (symbol . "t"))) -;;; auto-complete-dcd.el ends here +(provide 'ac-dcd) +;;; ac-dcd.el ends here From 710534576698bc05be625784b9ae926eddde2acb Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Wed, 18 Jun 2014 21:26:15 +0900 Subject: [PATCH 03/12] Update README.md Fix setting example --- editors/emacs/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editors/emacs/README.md b/editors/emacs/README.md index c1bd556..d7c2742 100644 --- a/editors/emacs/README.md +++ b/editors/emacs/README.md @@ -7,7 +7,7 @@ ## 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. - +``` (add-to-list 'load-path "path_to_ac-dcd.el") (require 'ac-dcd) (add-to-list 'ac-modes 'd-mode) @@ -16,7 +16,7 @@ (add-to-list 'ac-sources 'ac-source-dcd) (auto-complete-mode t)) (add-hook 'd-mode-hook 'ac-d-mode-setup) - +``` * 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```. @@ -25,4 +25,4 @@ * detailed ac-source symbol * goto definition * show doc -* and so on... \ No newline at end of file +* and so on... From f36520ad82d8937d4239278bcc54fa63e5984514 Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Mon, 23 Jun 2014 16:34:08 -0700 Subject: [PATCH 04/12] Update TA module --- editors/textadept/modules/dmd/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 07f0b05f80e50d16f205e28fd6bcb4ae566e39fd Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Mon, 23 Jun 2014 16:44:18 -0700 Subject: [PATCH 05/12] Updated dependencies --- containers | 2 +- dscanner | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/containers b/containers index 36a00d9..6e9aa02 160000 --- a/containers +++ b/containers @@ -1 +1 @@ -Subproject commit 36a00d9f109fde9c53db3173fae39439b007c0ce +Subproject commit 6e9aa02eda657fd0a3e820641cbcdecc3dfbd0ce diff --git a/dscanner b/dscanner index f54f782..ade1a71 160000 --- a/dscanner +++ b/dscanner @@ -1 +1 @@ -Subproject commit f54f7823dc62c14b7afb6b7db6e7693e79be34fa +Subproject commit ade1a718aced45992ecd232b1227c8779b9f9603 From e8bf51576918474f9924ecd94449c7b8b8144e53 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 24 Jun 2014 19:57:35 +0900 Subject: [PATCH 06/12] complete calltips, show doc support --- editors/emacs/ac-dcd.el | 289 ++++++++++++++++++++++++++-------------- 1 file changed, 191 insertions(+), 98 deletions(-) diff --git a/editors/emacs/ac-dcd.el b/editors/emacs/ac-dcd.el index 4addbb2..8d00e9c 100644 --- a/editors/emacs/ac-dcd.el +++ b/editors/emacs/ac-dcd.el @@ -22,6 +22,8 @@ ;;; Code: (require 'auto-complete) +(require 'rx) +(require 'yasnippet) (defcustom ac-dcd-executable "dcd-client" @@ -29,16 +31,18 @@ :group 'auto-complete :type 'file) -;;; Extra compilation flags to pass to dcd. (defcustom ac-dcd-flags nil "Extra flags to pass to the dcd-server. -This variable will typically contain include paths, e.g., (\"-I~/MyProject\", \"-I.\"). +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*") @@ -56,6 +60,7 @@ You can't put port number flag here. Set `ac-dcd-server-port' instead." "Duration after killing server process in milli second.") +;;server handle functions (defun ac-dcd-stop-server () "Stop dcd-server manually. Ordinary, you don't have to call it. @@ -87,34 +92,37 @@ If you want to restart server, use `ac-dcd-init-server' instead." (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 " "))) @@ -136,6 +144,7 @@ If you want to restart server, use `ac-dcd-init-server' instead." (goto-char (point-min)))))) +;; utility functions to call process (defun ac-dcd-call-process (prefix args) (let ((buf (get-buffer-create "*dcd-output*")) @@ -151,6 +160,11 @@ If you want to restart server, use `ac-dcd-init-server' instead." ;; 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) (list "-c" @@ -160,53 +174,20 @@ If you want to restart server, use `ac-dcd-init-server' instead." )) -(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) (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-build-complete-args (ac-dcd-cursor-position)))))) (defun ac-dcd-prefix () (or (ac-prefix-symbol) @@ -218,68 +199,180 @@ If you want to restart server, use `ac-dcd-init-server' instead." (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 (get-text-property 0 'ac-dcd-help lastcompl) "f") ; when it was a function + (progn + (insert "(") ;dcd-client requires open parenthesis to complete calltip. + (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) + (action . ac-dcd-action) (cache) - (symbol . "D"))) + (symbol . "D") + )) -(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))) + +;; function calltip expansion with yasnippet -(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-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 "*dcd-output*"))) + (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." + (ac-dcd-call-process + (concat (cdr ac-last-completion) "(") + (ac-dcd-build-complete-args (ac-dcd-cursor-position)))) + + +(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-remove-function-return-type (s) + "Remove return type of function." + (let ((sl (split-string s))) + (if (string-match "(" (car sl)) ; filter calltip candidate which has no return type. e.g. std.regex.match + s + (mapconcat 'identity (cdr sl) " ") + ))) + + +(defun ac-dcd-parse-calltips () + "Parse dcd output for calltips 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-remove-function-return-type (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 + ;; find the end of function name. some function arguments have parenthesis of its own, + ;; so I had to do it like this. + (search-backward (cdr ac-last-completion)) + (- (search-forward "(" ) 1))) + (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-get-ddoc (pos) + "Get document with `dcd-client --doc'. `POS' is cursor position. +TODO:reformat it." + (let ((args + (append + (ac-dcd-build-complete-args (ac-dcd-cursor-position)) + '("--doc") + (list (buffer-file-name)))) + (buf (get-buffer-create "*dcd-output*"))) + (with-current-buffer + buf (erase-buffer) + (apply 'call-process ac-dcd-executable nil buf nil args)) + (let ((raw-doc (with-current-buffer buf (buffer-string)))) + ;; ;; TODO: format document string. + ;; (setq raw-doc (replace-regexp-in-string + ;; (rx (and (not (any "\\\\")) (submatch "\\n"))) + ;; " " raw-doc nil nil 1 nil)); replace \n with space + ;; ;; (setq raw-doc (replace-regexp-in-string + ;; ;; (rx "\\n") "\n" raw-doc));replace \\n(RET in D src) with \n + ;; (setq raw-doc (replace-regexp-in-string + ;; (rx (and "$(D" (submatch (* anything)) ")")) + ;; " `\\1' " raw-doc)) ;format D src + raw-doc))) + +(defun ac-dcd-popup-ddoc-at-point () + "Popup Ddoc at point using popup.el." + (interactive) + (let ((doc (ac-dcd-get-ddoc (ac-dcd-cursor-position)))) + (when (or(string= doc "") + (string= doc "\n\n\n") ;when symbol has no doc + ) + (message "No document for the symbol at point!")))) -(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) - (cache) - (symbol . "t"))) - (provide 'ac-dcd) ;;; ac-dcd.el ends here From 6b8fcaad5643d9da7bbf29efc044f0628e0c0684 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 24 Jun 2014 20:05:57 +0900 Subject: [PATCH 07/12] Update README.md --- editors/emacs/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/editors/emacs/README.md b/editors/emacs/README.md index d7c2742..44df6d9 100644 --- a/editors/emacs/README.md +++ b/editors/emacs/README.md @@ -1,13 +1,14 @@ -#EMACS Integration +#Emacs Integration ##Requirements -* You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package. +* You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package, and [yasnippet](https://github.com/capitaomorte/yasnippet) package 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```. ## 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. ``` +;;; ac-dcd (add-to-list 'load-path "path_to_ac-dcd.el") (require 'ac-dcd) (add-to-list 'ac-modes 'd-mode) @@ -16,13 +17,15 @@ (add-to-list 'ac-sources 'ac-source-dcd) (auto-complete-mode t)) (add-hook 'd-mode-hook 'ac-d-mode-setup) + +(define-key d-mode-map (kbd "C-c C-h") 'ac-dcd-popup-ddoc-at-point) ;of course, you can change this keybind. + ``` + * 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```. ## TODO -* better error detection -* detailed ac-source symbol * goto definition -* show doc +* Multi byte character support (Need help!) * and so on... From 337efaa30362858eab2437faa77f97027abca00a Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Wed, 25 Jun 2014 19:13:57 +0900 Subject: [PATCH 08/12] Update README.md --- editors/emacs/README.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/editors/emacs/README.md b/editors/emacs/README.md index 44df6d9..1b1e60f 100644 --- a/editors/emacs/README.md +++ b/editors/emacs/README.md @@ -1,31 +1,40 @@ #Emacs Integration ##Requirements -* You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package, and [yasnippet](https://github.com/capitaomorte/yasnippet) package is recommended. +* You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package. +And [yasnippet](https://github.com/capitaomorte/yasnippet) package 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```. ## 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. + ``` ;;; ac-dcd (add-to-list 'load-path "path_to_ac-dcd.el") (require 'ac-dcd) (add-to-list 'ac-modes 'd-mode) -(defun ac-d-mode-setup () - (ac-dcd-maybe-start-server) - (add-to-list 'ac-sources 'ac-source-dcd) - (auto-complete-mode t)) -(add-hook 'd-mode-hook 'ac-d-mode-setup) -(define-key d-mode-map (kbd "C-c C-h") 'ac-dcd-popup-ddoc-at-point) ;of course, you can change this keybind. +(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-popup-ddoc-at-point) +(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) ``` * 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 -* goto definition +* Better error handling * Multi byte character support (Need help!) -* and so on... From 8c740965dc5cfc62ae9f6289c7ce906a07e2de32 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Wed, 25 Jun 2014 19:16:05 +0900 Subject: [PATCH 09/12] Goto definition support, bug fix --- editors/emacs/ac-dcd.el | 88 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/editors/emacs/ac-dcd.el b/editors/emacs/ac-dcd.el index 8d00e9c..c704fb0 100644 --- a/editors/emacs/ac-dcd.el +++ b/editors/emacs/ac-dcd.el @@ -274,9 +274,9 @@ When the symbol is not a function, returns nothing" \\1 is function return type (if exists) and name, and \\2 is args.") (defsubst ac-dcd-remove-function-return-type (s) - "Remove return type of function." + "Remove return type of the function." (let ((sl (split-string s))) - (if (string-match "(" (car sl)) ; filter calltip candidate which has no return type. e.g. std.regex.match + (if (string-match "(" (car sl)) ; s (mapconcat 'identity (cdr sl) " ") ))) @@ -312,7 +312,7 @@ This function should be called at *dcd-output* buf." yasstr) (setq kill-ring (cdr kill-ring)); clean up kill-ring - ;remove parenthesis + ;;remove parenthesis (setq str (substring str 1 (- (length str) 1))) (setq yasstr @@ -342,6 +342,7 @@ This function should be called at *dcd-output* buf." (defun ac-dcd-get-ddoc (pos) "Get document with `dcd-client --doc'. `POS' is cursor position. TODO:reformat it." + (save-buffer) (let ((args (append (ac-dcd-build-complete-args (ac-dcd-cursor-position)) @@ -370,9 +371,88 @@ TODO:reformat it." (when (or(string= doc "") (string= doc "\n\n\n") ;when symbol has no doc ) - (message "No document for the symbol at point!")))) + (message "No document for the symbol at point!")) + (popup-tip doc))) +;; 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)) + '("--symbolLocation") + (list (buffer-file-name)))) + (buf (get-buffer-create "*dcd-output*"))) + (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 "*dcd-output*"))) + (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 From 3aba4955e5d3998726c05e1ca4cba2d74b1bf32b Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Thu, 26 Jun 2014 12:44:51 -0700 Subject: [PATCH 10/12] Use libdparse instead of dscanner --- .gitmodules | 7 ++++--- autocomplete.d | 3 +-- build.sh | 14 +++++++------- containers | 2 +- conversion/astconverter.d | 3 ++- conversion/first.d | 2 +- conversion/third.d | 2 +- dscanner | 1 - libdparse | 1 + modulecache.d | 6 +----- 10 files changed, 19 insertions(+), 22 deletions(-) delete mode 160000 dscanner create mode 160000 libdparse 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.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 6e9aa02..2a72525 160000 --- a/containers +++ b/containers @@ -1 +1 @@ -Subproject commit 6e9aa02eda657fd0a3e820641cbcdecc3dfbd0ce +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 ade1a71..0000000 --- a/dscanner +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ade1a718aced45992ecd232b1227c8779b9f9603 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 1fe21c9..5d13a84 100644 --- a/modulecache.d +++ b/modulecache.d @@ -137,7 +137,6 @@ struct ModuleCache ACSymbol*[] symbols; // try // { - import core.memory; 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); From 21961bbc6fa88e4c5c34f1087dee38356e0fbab9 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Fri, 4 Jul 2014 20:31:23 +0900 Subject: [PATCH 11/12] Add recommended package, update setup example --- editors/emacs/README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/editors/emacs/README.md b/editors/emacs/README.md index 1b1e60f..2cf9285 100644 --- a/editors/emacs/README.md +++ b/editors/emacs/README.md @@ -2,12 +2,12 @@ ##Requirements * You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package. -And [yasnippet](https://github.com/capitaomorte/yasnippet) package is recommended. +[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```. ## 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. +* 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 @@ -20,9 +20,13 @@ And [yasnippet](https://github.com/capitaomorte/yasnippet) package is recommende (ac-dcd-maybe-start-server) (add-to-list 'ac-sources 'ac-source-dcd))) -(define-key d-mode-map (kbd "C-c ?") 'ac-dcd-popup-ddoc-at-point) +(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```. From a6f18442d58c1afc37bfba3ce36ee220f39f4c5a Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Fri, 4 Jul 2014 20:33:46 +0900 Subject: [PATCH 12/12] Bug fix Fix bug of calltip expansion. Fix bug of show document. --- editors/emacs/ac-dcd.el | 145 ++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 52 deletions(-) diff --git a/editors/emacs/ac-dcd.el b/editors/emacs/ac-dcd.el index c704fb0..6816a3f 100644 --- a/editors/emacs/ac-dcd.el +++ b/editors/emacs/ac-dcd.el @@ -24,7 +24,7 @@ (require 'auto-complete) (require 'rx) (require 'yasnippet) - +(require 'eshell) (defcustom ac-dcd-executable "dcd-client" "Location of dcd-client executable." @@ -44,8 +44,9 @@ You can't put port number flag here. Set `ac-dcd-server-port' instead." "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." @@ -57,7 +58,8 @@ You can't put port number flag here. Set `ac-dcd-server-port' instead." :group 'auto-complete) (defvar ac-dcd-delay-after-kill-process 200 - "Duration after killing server process in milli second.") + "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 @@ -147,7 +149,7 @@ If you want to restart server, use `ac-dcd-init-server' instead." ;; utility functions to call process (defun ac-dcd-call-process (prefix args) - (let ((buf (get-buffer-create "*dcd-output*")) + (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) @@ -232,9 +234,8 @@ TODO: multi byte character support" (let ((lastcompl (cdr ac-last-completion))) (cond - ((equal (get-text-property 0 'ac-dcd-help lastcompl) "f") ; when it was a function + ((equal "f" (get-text-property 0 'ac-dcd-help lastcompl)) ; when it was a function (progn - (insert "(") ;dcd-client requires open parenthesis to complete calltip. (ac-complete-dcd-calltips))) (t nil) )))) @@ -256,16 +257,24 @@ TODO: multi byte character support" "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 "*dcd-output*"))) + (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)))) + (ac-dcd-build-complete-args (ac-dcd-cursor-position))) + + (forward-char 2) + (delete-char -3) + + ) (defconst ac-dcd-calltip-pattern @@ -273,17 +282,31 @@ When the symbol is not a function, returns nothing" "Regexp to parse calltip completion output. \\1 is function return type (if exists) and name, and \\2 is args.") -(defsubst ac-dcd-remove-function-return-type (s) - "Remove return type of the function." - (let ((sl (split-string s))) - (if (string-match "(" (car sl)) ; - s - (mapconcat 'identity (cdr sl) " ") +(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 calltips completion. + "Parse dcd output for calltip completion. It returns a list of calltip candidates." (goto-char (point-min)) (let ((pattern ac-dcd-calltip-pattern) @@ -291,7 +314,10 @@ It returns a list of calltip candidates." match (prev-match "")) (while (re-search-forward pattern nil t) - (setq match (ac-dcd-remove-function-return-type (concat (match-string-no-properties 1) (match-string-no-properties 2)))) + (setq match + (ac-dcd-cleanup-function-candidate + (concat (match-string-no-properties 1) (match-string-no-properties 2)) + )) (push match lines)) lines )) @@ -303,10 +329,9 @@ This function should be called at *dcd-output* buf." (save-excursion (setq end (point)) (setq beg (progn - ;; find the end of function name. some function arguments have parenthesis of its own, - ;; so I had to do it like this. - (search-backward (cdr ac-last-completion)) - (- (search-forward "(" ) 1))) + (backward-sexp) + (point) + )) (kill-region beg end)) (let ((str (car kill-ring)) yasstr) @@ -324,7 +349,8 @@ This function should be called at *dcd-output* buf." ;; ;;debug ;; (message (format "str: %s" str)) ;; (message (format "yasstr: %s" yasstr)) - (yas-expand-snippet yasstr)))) + (yas-expand-snippet yasstr) + ))) (defun ac-dcd-calltip-prefix () (car ac-last-completion)) @@ -339,40 +365,55 @@ This function should be called at *dcd-output* buf." ;;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. -TODO:reformat it." + "Get document with `dcd-client --doc'. `POS' is cursor position." (save-buffer) (let ((args (append (ac-dcd-build-complete-args (ac-dcd-cursor-position)) - '("--doc") + '("-d") (list (buffer-file-name)))) - (buf (get-buffer-create "*dcd-output*"))) - (with-current-buffer - buf (erase-buffer) - (apply 'call-process ac-dcd-executable nil buf nil args)) - (let ((raw-doc (with-current-buffer buf (buffer-string)))) - ;; ;; TODO: format document string. - ;; (setq raw-doc (replace-regexp-in-string - ;; (rx (and (not (any "\\\\")) (submatch "\\n"))) - ;; " " raw-doc nil nil 1 nil)); replace \n with space - ;; ;; (setq raw-doc (replace-regexp-in-string - ;; ;; (rx "\\n") "\n" raw-doc));replace \\n(RET in D src) with \n - ;; (setq raw-doc (replace-regexp-in-string - ;; (rx (and "$(D" (submatch (* anything)) ")")) - ;; " `\\1' " raw-doc)) ;format D src - raw-doc))) + (buf (get-buffer-create ac-dcd-document-buffer-name))) -(defun ac-dcd-popup-ddoc-at-point () - "Popup Ddoc at point using popup.el." - (interactive) - (let ((doc (ac-dcd-get-ddoc (ac-dcd-cursor-position)))) - (when (or(string= doc "") - (string= doc "\n\n\n") ;when symbol has no doc + ;; 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 ) - (message "No document for the symbol at point!")) - (popup-tip 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 @@ -431,9 +472,9 @@ TODO:reformat it." (let ((args (append (ac-dcd-build-complete-args (ac-dcd-cursor-position)) - '("--symbolLocation") + '("-l") (list (buffer-file-name)))) - (buf (get-buffer-create "*dcd-output*"))) + (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)) @@ -444,7 +485,7 @@ TODO:reformat it." "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 "*dcd-output*"))) + (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)))