├── .gitignore ├── README.md ├── UNLICENSE ├── javadoc-import.el ├── javadoc-lookup.el ├── maven-fetch.el └── webcache └── http+++docs.oracle.com+javase+8+docs+api+.v4 /.gitignore: -------------------------------------------------------------------------------- 1 | *.elc 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # javadoc-lookup 2 | 3 | This package provides a `javadoc-lookup` function for quickly looking 4 | up Javadoc for any library from within Emacs, optionally integrating 5 | with Maven. A browser is launched to view the documentation. 6 | 7 | `javadoc-lookup` is not bound to any key by default, so you may want 8 | to add this to your initialization file, 9 | 10 | ```el 11 | (global-set-key (kbd "C-h j") 'javadoc-lookup) 12 | ```` 13 | 14 | An index for the core Java classes (i.e. java.*) is provided 15 | built-in. Beyond this, you'll want to tell javadoc-lookup what else 16 | you would like to have indexed. There are two ways to do this. You can 17 | point it to the root of a library's documentation on your 18 | filesystem. For example (the first entry here will replace the 19 | built-in index), 20 | 21 | ```el 22 | (javadoc-add-roots "/usr/share/doc/openjdk-8-jdk/api" 23 | "~/src/project/doc") 24 | ``` 25 | 26 | Or, more conveniently, you can **fetch and index documentation from 27 | Maven**! This is done by specifying an artifact as a sequence of three 28 | strings/symbols: `[groupId artifactId version]`. For example, 29 | 30 | ```el 31 | (javadoc-add-artifacts [org.lwjgl.lwjg lwjgl "2.8.2"] 32 | [com.nullprogram native-guide "0.2"] 33 | [org.apache.commons commons-math3 "3.0"]) 34 | ``` 35 | 36 | This feature requires that you have Maven and the command-line unzip 37 | utility installed on your system. The initial fetch is slow but Emacs 38 | will operate from its own cache after that. 39 | 40 | ## Import functions 41 | 42 | Two functions for managing Java imports is provided: `javadoc-add-import` 43 | and `javadoc-sort-imports`. The former integrates with the javadoc-lookup 44 | index to provide completions. 45 | 46 | ## History 47 | 48 | This package obsoletes my previous java-docs package. Use this one 49 | instead. 50 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /javadoc-import.el: -------------------------------------------------------------------------------- 1 | ;;; javadoc-import.el --- quickly add import statements in Java 2 | 3 | ;; This is free and unencumbered software released into the public domain. 4 | 5 | ;;; Commentary: 6 | 7 | ;; Provides the functions `javadoc-add-import' and `javadoc-sort-imports'. 8 | 9 | ;;; Code: 10 | 11 | (require 'javadoc-lookup) 12 | 13 | (defvar jdl/import-regexp "^import " 14 | "Regular expression for finding import statements.") 15 | 16 | (defvar jdl/package-regexp "^package " 17 | "Regular expression for finding package statements.") 18 | 19 | (defun jdl/in-package () 20 | "Return t if this source has a package statement." 21 | (save-excursion 22 | (goto-char (point-min)) 23 | (and (search-forward-regexp jdl/package-regexp nil t) t))) 24 | 25 | (defun jdl/has-import () 26 | "Return t if this source has at least one import statement." 27 | (save-excursion 28 | (goto-char (point-min)) 29 | (and (search-forward-regexp jdl/import-regexp nil t) t))) 30 | 31 | (defun jdl/goto-first-import () 32 | "Move cursor to the first import statement." 33 | (goto-char (point-min)) 34 | (search-forward-regexp jdl/import-regexp) 35 | (move-beginning-of-line nil) 36 | (point)) 37 | 38 | (defun jdl/goto-last-import () 39 | "Move cursor to the first import statement." 40 | (goto-char (point-max)) 41 | (search-backward-regexp jdl/import-regexp) 42 | (move-end-of-line nil) 43 | (forward-char) 44 | (point)) 45 | 46 | ;;;###autoload 47 | (defun javadoc-sort-imports () 48 | "Sort the imports in the import section in proper order." 49 | (interactive) 50 | (when (jdl/has-import) 51 | (save-excursion 52 | (sort-lines nil (jdl/goto-first-import) (jdl/goto-last-import))))) 53 | 54 | ;;;###autoload 55 | (define-obsolete-function-alias 56 | 'sort-java-imports 'javadoc-sort-imports "1.1.0") 57 | 58 | ;;;###autoload 59 | (defun javadoc-add-import () 60 | "Insert an import statement at import section at the top of the file." 61 | (interactive) 62 | (let ((class (jdl/completing-read))) 63 | (save-excursion 64 | (if (jdl/has-import) 65 | (progn 66 | (jdl/goto-first-import) 67 | (insert "import " class ";\n") 68 | (javadoc-sort-imports)) 69 | (progn 70 | (goto-char (point-min)) 71 | (when (jdl/in-package) 72 | (search-forward-regexp jdl/package-regexp) 73 | (move-end-of-line nil) 74 | (forward-char) 75 | (insert "\n")) 76 | (insert "import " class ";\n")))))) 77 | 78 | ;;;###autoload 79 | (define-obsolete-function-alias 80 | 'add-java-import 'javadoc-add-import "1.1.0") 81 | 82 | (provide 'javadoc-import) 83 | 84 | ;;; javadoc-import.el ends here 85 | -------------------------------------------------------------------------------- /javadoc-lookup.el: -------------------------------------------------------------------------------- 1 | ;;; javadoc-lookup.el --- Javadoc Emacs integration with Maven 2 | 3 | ;; This is free and unencumbered software released into the public domain. 4 | 5 | ;; Author: Christopher Wellons 6 | ;; URL: https://github.com/skeeto/javadoc-lookup 7 | ;; Version: 1.1.0 8 | ;; Package-Requires: ((cl-lib "0.3")) 9 | 10 | ;;; Commentary: 11 | 12 | ;; This package provides a quick way to look up any Javadoc 13 | ;; documentation from Emacs, using your browser to display the 14 | ;; information. Since the mechanism is already there, java-import.el 15 | ;; provides the completing function `javadoc-add-import' for quickly 16 | ;; adding an import to a source file. 17 | 18 | ;; This mode stores database and index information in 19 | ;; `javadoc-lookup-cache-dir'. 20 | 21 | ;; Indexing: 22 | 23 | ;; Give `javadoc-lookup' your root Java documentation directories. It 24 | ;; will scan and index those directories, exposing them to 25 | ;; `javadoc-lookup'. Multiple directories can be provided at once, for 26 | ;; example, 27 | 28 | ;; (javadoc-add-roots "/usr/share/doc/openjdk-6-jdk/api" 29 | ;; "~/src/project/doc") 30 | 31 | ;; If you haven't loaded the core Java Javadoc, it will load a 32 | ;; pre-made database for you, which indexes the official website. 33 | 34 | ;; More conveniently, you can list Maven artifacts to index, 35 | 36 | ;; (javadoc-add-artifacts [org.lwjgl.lwjgl lwjgl "2.8.2"] 37 | ;; [com.nullprogram native-guide "0.2"] 38 | ;; [org.apache.commons commons-math3 "3.0"]) 39 | 40 | ;; Browser configuration: 41 | 42 | ;; To view documentation, the browser is launched with `browse-url'. 43 | ;; This may require setting `browse-url-browser-function' in order to 44 | ;; select the proper browser. For example, 45 | 46 | ;; (setq browse-url-browser-function 'browse-url-firefox) 47 | 48 | ;;; Code: 49 | 50 | (require 'cl-lib) 51 | (require 'ido) 52 | 53 | (defgroup javadoc-lookup () 54 | "Lookup Java library documentation from Emacs." 55 | :group 'java) 56 | 57 | ;; Customization variables 58 | 59 | (defcustom javadoc-lookup-cache-dir (locate-user-emacs-file "javadoc-cache") 60 | "Filesystem location to store index and cache database.") 61 | 62 | (defcustom javadoc-lookup-completing-read-function #'ido-completing-read 63 | "Function used when performing a minibuffer read.") 64 | 65 | ;; Internal variables 66 | 67 | (defvar jdl/data-root (file-name-directory load-file-name) 68 | "The location of data for javadoc-loookup.") 69 | 70 | (defvar jdl/index (make-hash-table :test 'equal) 71 | "Full index of for documentation lookups.") 72 | 73 | (defvar jdl/cache-version ".v4" 74 | "Cache version, so it won't load old caches.") 75 | 76 | (defvar jdl/loaded () 77 | "List of already-loaded documentation directories.") 78 | 79 | ;; Indexing Functions 80 | 81 | (defun jdl/dir-truename (dir) 82 | "Return the truename for DIR, which always has a trailing slash." 83 | (expand-file-name (concat dir "/"))) 84 | 85 | (defun jdl/clear () 86 | "Clear all in-memory javadoc-lookup cache and indexes." 87 | (setq jdl/loaded nil) 88 | (setq jdl/index (make-hash-table :test 'equal))) 89 | 90 | (defun jdl/loaded-p (dir) 91 | "Return t if DIR has already been loaded." 92 | (member dir jdl/loaded)) 93 | 94 | (defun jdl/cache-name (dir) 95 | "Get the cache file name for DIR." 96 | (concat (replace-regexp-in-string "[/:]" "+" dir) jdl/cache-version)) 97 | 98 | (defun jdl/load-cache (cache-file) 99 | "Load a cache from disk." 100 | (let ((require-final-newline nil)) 101 | (with-current-buffer (find-file-noselect cache-file) 102 | (goto-char (point-min)) 103 | (jdl/add-hash (read (current-buffer))) 104 | (kill-buffer)))) 105 | 106 | (defun jdl/save-cache (cache-file hash) 107 | "Save a cache to the disk." 108 | (unless (file-exists-p javadoc-lookup-cache-dir) 109 | (make-directory javadoc-lookup-cache-dir t)) 110 | (with-temp-file cache-file 111 | (let ((print-circle t) 112 | (print-level nil) 113 | (print-length nil)) 114 | (prin1 hash (current-buffer))))) 115 | 116 | (defun jdl/add (dir) 117 | "Index DIR, using the cache if available." 118 | (let ((cache-file (expand-file-name (jdl/cache-name dir) 119 | javadoc-lookup-cache-dir))) 120 | (if (file-exists-p cache-file) 121 | (jdl/load-cache cache-file) 122 | (let ((hash (make-hash-table :test 'equal))) 123 | (jdl/index dir hash) 124 | (jdl/save-cache cache-file hash) 125 | (jdl/add-hash hash)))) 126 | (add-to-list 'jdl/loaded dir)) 127 | 128 | (defun jdl/add-hash (hash) 129 | "Combine HASH into the main index hash." 130 | (maphash (lambda (key val) (puthash key val jdl/index)) hash)) 131 | 132 | (cl-defun jdl/index (dir hash &optional (root (list dir "file://"))) 133 | "Index the documentation in DIR into HASH, based on ROOT." 134 | (let* ((list (directory-files dir t "^[^.]")) 135 | (files (cl-remove-if 'file-directory-p list)) 136 | (dirs (cl-remove-if-not 'file-directory-p list))) 137 | (dolist (file files) 138 | (jdl/add-file file hash root)) 139 | (dolist (dir dirs) 140 | (when (not (string-equal "class-use" (file-name-nondirectory dir))) 141 | (jdl/index dir hash root))))) 142 | 143 | (defun jdl/add-file (fullfile hash root) 144 | "Add a file to the index if it looks like a class." 145 | (let* ((file (file-name-nondirectory fullfile)) 146 | (ext (file-name-extension fullfile)) 147 | (class (file-name-sans-extension file)) 148 | (rel (substring fullfile (length (cl-first root)))) 149 | (fullclass (cl-substitute ?. ?/ (file-name-sans-extension rel))) 150 | (case-fold-search nil)) 151 | (when (and (string-equal ext "html") 152 | (string-match "^[A-Z].+" class)) 153 | (puthash fullclass (cons rel root) hash)))) 154 | 155 | (defun javadoc-add-roots (&rest directories) 156 | "Index and load all documentation under DIRECTORIES." 157 | (cl-loop for directory in directories 158 | for truename = (jdl/dir-truename directory) 159 | unless (jdl/loaded-p truename) 160 | do (jdl/add truename))) 161 | 162 | (defun jdl/web (&rest urls) 163 | "Load pre-cached web indexes for URLS." 164 | (dolist (url (cl-remove-if 'jdl/loaded-p urls)) 165 | (let* ((rel-cache-file (concat "webcache/" (jdl/cache-name url))) 166 | (cache-file (expand-file-name rel-cache-file jdl/data-root))) 167 | (if (file-exists-p cache-file) 168 | (jdl/load-cache cache-file) 169 | (error "No cache for %s" url))))) 170 | 171 | ;; Lookup functions 172 | 173 | (defun jdl/core-indexed-p () 174 | "Return true if the JRE Javadoc has been indexed. The class 175 | java.net.URL is used for this test, since it's simple and should 176 | always be there." 177 | (gethash "java.net.URL" jdl/index)) 178 | 179 | (defun jdl/get-class-list () 180 | (cl-loop for class being the hash-keys of jdl/index 181 | collect class into classes 182 | finally (return (cl-sort classes #'< :key #'length)))) 183 | 184 | (defun jdl/completing-read () 185 | "Query the user for a class name." 186 | (unless (jdl/core-indexed-p) 187 | (ignore-errors ; Provide *something* useful, if needed 188 | (jdl/web "http://docs.oracle.com/javase/8/docs/api/"))) 189 | (let ((default (thing-at-point 'symbol)) 190 | (classes (jdl/get-class-list))) 191 | (funcall javadoc-lookup-completing-read-function "Class: " 192 | classes nil nil nil nil 193 | (and default (cl-find default classes :test #'string-match))))) 194 | 195 | ;;;###autoload 196 | (defun javadoc-lookup (name) 197 | "Lookup based on class name." 198 | (interactive (list (jdl/completing-read))) 199 | (let ((file (apply #'concat (reverse (gethash name jdl/index))))) 200 | (when file (browse-url file)))) 201 | 202 | (provide 'javadoc-lookup) 203 | 204 | ;;; javadoc-lookup.el ends here 205 | -------------------------------------------------------------------------------- /maven-fetch.el: -------------------------------------------------------------------------------- 1 | ;;; maven-fetch.el --- Fetch Javadoc artifacts from the Maven repository 2 | 3 | ;; This is free and unencumbered software released into the public domain. 4 | 5 | ;;; Commentary: 6 | 7 | ;; This code adds support to javadoc-lookup by automatically fetching 8 | ;; and indexing documentation artifacts from the Maven repository. It 9 | ;; requires Maven and the command-line unzip utility installed on your 10 | ;; system. If these are not in your $PATH, the variables 11 | ;; `maven-program-name' and `unzip-program-name' will need to be set. 12 | 13 | ;; An artifact is specified by a sequence (list or vector) of three 14 | ;; strings: [groupId artifactId version]. For example, 15 | 16 | ;; ["org.apache.commons" "commons-math3" "3.0"] 17 | 18 | ;; In your Emacs initialization file, call `javadoc-add-artifact' with 19 | ;; your desired artifacts. They are only downloaded, unzipped, and 20 | ;; indexed -- a slow process -- the very first time. Each startup 21 | ;; after that, Emacs will work entirely from a cache (fast). 22 | 23 | ;;; Code: 24 | 25 | (require 'cl-lib) 26 | (require 'javadoc-lookup) 27 | 28 | (defcustom maven-program-name "mvn" 29 | "Path to the Maven executable." 30 | :group 'external) 31 | 32 | (defcustom unzip-program-name "unzip" 33 | "Path to the unzip executable." 34 | :group 'external) 35 | 36 | (defvar maven-fetch-command 37 | "org.apache.maven.plugins:maven-dependency-plugin:2.6:get" 38 | "Long command name for the Maven dependency fetch plugin.") 39 | 40 | (defun maven-fetch-artifact-jar (artifact) 41 | "Return the cache filename for ARTIFACT." 42 | (let ((file (format "%s-%s-javadoc.jar" (elt artifact 1) (elt artifact 2)))) 43 | (expand-file-name file (jdl/dir-truename javadoc-lookup-cache-dir)))) 44 | 45 | (defun maven-fetch-unpacked-path (artifact) 46 | "Return the unpacked directory name for ARTIFACT." 47 | (expand-file-name (format "%s/%s" (elt artifact 0) (elt artifact 1)) 48 | (jdl/dir-truename javadoc-lookup-cache-dir))) 49 | 50 | (cl-defun maven-fetch (artifact) 51 | "Use maven to fetch ARTIFACT into the cache directory, 52 | returning true on success." 53 | (let ((jarfile (maven-fetch-artifact-jar artifact))) 54 | (if (file-exists-p jarfile) 55 | (format "Artifact %s already downloaded" artifact) 56 | (let ((artifact-arg "-Dartifact=%s:%s:%s:javadoc")) 57 | (message "Maven is fetching %s ..." artifact) 58 | (zerop 59 | (call-process maven-program-name nil nil nil 60 | maven-fetch-command 61 | (format "-Ddest=%s" jarfile) 62 | (apply #'format artifact-arg 63 | (cl-coerce artifact 'list)))))))) 64 | 65 | (defun maven-fetch-unpack (artifact) 66 | "Unpack an artifact in the javadoc-lookup cache directory, 67 | returning the destination directory. Throws an error on any failure." 68 | (let* ((jarfile (maven-fetch-artifact-jar artifact)) 69 | (destdir (maven-fetch-unpacked-path artifact))) 70 | (if (not (file-exists-p jarfile)) 71 | (error "Could not find artifact jar file: %s." jarfile) 72 | (if (file-exists-p destdir) 73 | destdir 74 | (message "Unpacking %s ..." (file-name-nondirectory jarfile)) 75 | (mkdir destdir t) 76 | (if (call-process unzip-program-name nil nil nil jarfile "-d" destdir) 77 | destdir 78 | (delete-directory destdir t) 79 | (error "Failed to unpack %s" jarfile)))))) 80 | 81 | ;;;###autoload 82 | (defun javadoc-add-artifacts (&rest artifacts) 83 | "Add Maven repository artifacts to the javadoc-lookup index. 84 | An artifact is specified by a sequence of three strings: 85 | [groupId artifactId version]." 86 | (dolist (artifact artifacts) 87 | (if (maven-fetch artifact) 88 | (javadoc-add-roots (maven-fetch-unpack artifact)) 89 | (error "Failed to fetch %s" artifact)))) 90 | 91 | (provide 'maven-fetch) 92 | 93 | ;;; maven-fetch.el ends here 94 | --------------------------------------------------------------------------------