diff --git a/editors/emacs/README.md b/editors/emacs/README.md index 2056f2d..fbfc019 100644 --- a/editors/emacs/README.md +++ b/editors/emacs/README.md @@ -1,47 +1,59 @@ -#Emacs Integration +# Emacs Integration -##Requirements -* You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package. -And, [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```. +## Requirements + +* You must have the +[auto-complete](https://github.com/auto-complete/auto-complete) package. Also, +[yasnippet](https://github.com/capitaomorte/yasnippet) and +[popwin](https://github.com/m2ym/popwin-el) are recommended. +* Make sure `dcd-client` and `dcd-server` are in your exec-path. Otherwise, + please set the variables `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. (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) +* Follow the Setup section in the root README. +* 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 environment.) -(add-hook 'd-mode-hook - '(lambda () "set up ac-dcd" - (auto-complete-mode t) - (yas-minor-mode-on) - (ac-dcd-maybe-start-server) - (add-to-list 'ac-sources 'ac-source-dcd))) + ;;; ac-dcd + (add-to-list 'load-path "path_to_ac-dcd.el") + (require 'ac-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) + (add-hook 'd-mode-hook + '(lambda () "set up ac-dcd" + (auto-complete-mode t) + (yas-minor-mode-on) + (ac-dcd-maybe-start-server) + (add-to-list 'ac-sources 'ac-source-dcd))) -(when (featurep 'popwin) - (add-to-list 'popwin:special-display-config - `(,ac-dcd-error-buffer-name :noselect t)) - (add-to-list 'popwin:special-display-config - `(,ac-dcd-document-buffer-name :position right :width 80))) + (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-error-buffer-name :noselect t)) + (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```. +* You can set import paths using `M-x customize-variable RET ac-dcd-flags`. +* Alternatively, if you're using [DUB](http://code.dlang.org/) to manage your + project, you can use `M-x ac-dcd-add-imports` to add import paths of the + current project automatically. +* 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 ,``` +* Show ddoc with `C-c ?` +* Goto definition with `C-c .` +* After goto definition, you can pop to previous position with `C-c ,` ## TODO -* Multi byte character support (Need help!) + +* UTF-8 support is in place. However, UTF-16 and UTF-32 may not work correctly. + (Need help!) diff --git a/editors/emacs/ac-dcd.el b/editors/emacs/ac-dcd.el index 82f09db..08e95c6 100644 --- a/editors/emacs/ac-dcd.el +++ b/editors/emacs/ac-dcd.el @@ -527,6 +527,86 @@ output is just like following.\n (cons nil nil))) )) +(defun ac-dcd-parent-directory (dir) + "Returns parent directory of dir" + (when dir + (file-name-directory (directory-file-name (expand-file-name dir))))) + +(defun ac-dcd-search-file-up (name &optional path) + "Searches for file `name' in parent directories recursively" + (let* ((tags-file-name (concat path name)) + (parent (ac-dcd-parent-directory path)) + (path (or path default-directory)) + ) + (cond + ((file-exists-p tags-file-name) tags-file-name) + ((string= parent path) nil) + (t (ac-dcd-search-file-up name parent))))) + +(defun ac-dcd-find-imports-dub () + "Extract import flags from \"dub describe\" output." + (let ((dub-root-dir (ac-dcd-parent-directory + (or (ac-dcd-search-file-up "dub.json" default-directory) + (ac-dcd-search-file-up "package.json" default-directory)))) + (dub-executable "dub")) + + (when dub-root-dir + (with-temp-buffer + (let ((default-directory dub-root-dir)) + (call-process dub-executable nil (current-buffer) nil "describe")) + (require 'json) + (let* ((json-object-type 'hash-table) + (describe-hash (json-read-from-string (buffer-string))) + (packages-array (gethash "packages" describe-hash)) + (imports-list '())) + (mapcar + (lambda (package) + (let ((package-path (gethash "path" package)) + (import-paths-array (gethash "importPaths" package))) + (mapcar + (lambda (import-path) + (add-to-list 'imports-list + (concat "-I" package-path import-path))) + import-paths-array))) + packages-array) + imports-list))))) + +(defun ac-dcd-find-imports-std () + "Extract import flags from dmd.conf file." + (require 'cl) + (let ((dmd-conf-filename + (find-if 'file-exists-p + (list + ;; TODO: the first directory to look into should be dmd's current + ;; working dir + (concat (getenv "HOME") "/dmd.conf") + (concat (ac-dcd-parent-directory (executable-find "dmd")) "dmd.conf") + "/etc/dmd.conf")))) + + ;; TODO: this extracting procedure is pretty rough, it just searches for + ;; the first occurrence of the DFLAGS + (save-window-excursion + (with-temp-buffer + (find-file dmd-conf-filename) + (goto-char (point-min)) + (search-forward "\nDFLAGS") + (skip-chars-forward " =") + (let ((flags-list (split-string (buffer-substring-no-properties + (point) (line-end-position))))) + (remove-if-not '(lambda (s) + (string-prefix-p "-I" s)) + flags-list)))))) + +(defun ac-dcd-add-imports () + "Send import flags of the current DUB project to dcd-server. + +The root of the project is determined by the \"closest\" dub.json +or package.json file." + (interactive) + (ac-dcd-call-process "" + (append + (ac-dcd-find-imports-std) + (ac-dcd-find-imports-dub)))) (provide 'ac-dcd) ;;; ac-dcd.el ends here