[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/devdocs 257813d 3/7: Cache document index with timeout
From: |
ELPA Syncer |
Subject: |
[elpa] externals/devdocs 257813d 3/7: Cache document index with timeout |
Date: |
Sat, 29 May 2021 14:57:12 -0400 (EDT) |
branch: externals/devdocs
commit 257813d20a40060cf52abfaaab67a910a91c8b69
Author: Augusto Stoffel <arstoffel@gmail.com>
Commit: Augusto Stoffel <arstoffel@gmail.com>
Cache document index with timeout
---
evdocs.el | 135 ++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 75 insertions(+), 60 deletions(-)
diff --git a/evdocs.el b/evdocs.el
index 07e53ad..ca7f532 100644
--- a/evdocs.el
+++ b/evdocs.el
@@ -51,11 +51,16 @@
"Location of the DevDocs CDN.")
(defcustom evdocs-timeout 300
- "Number of seconds to keep cached document indexes.")
+ "Number of seconds to keep cached document indexes."
+ :type 'number)
(defcustom evdocs-separator " » "
"String used to format a documentation location, e.g. in header line.")
+(defvar evdocs--index (make-hash-table :test 'equal)
+ "A hash table to cache document indices.
+To be accessed through the function `evdocs--index'.")
+
;;; Documentation management
(defvar evdocs--doc-metadata (make-hash-table :test 'equal)
@@ -64,13 +69,14 @@ To be accessed through the function
`evdocs--doc-metadata'.")
(defun evdocs--doc-metadata (doc &optional refresh)
"Return the metadata for a document DOC.
-Also populates `evdocs--doc-metadata' if necessary, either from
-data on disk if REFRESH is nil, or from freshly downloaded data
-otherwise."
+Also populates the variable `evdocs--doc-metadata' if necessary,
+either from data on disk if REFRESH is nil, or from freshly
+downloaded data otherwise."
(when (or refresh (hash-table-empty-p evdocs--doc-metadata))
(let* ((file (expand-file-name "docs.json" evdocs-data-dir))
(docs (if (or refresh (not (file-exists-p file)))
(with-temp-file file
+ (make-directory (file-name-directory file) t)
(url-insert-file-contents (format "%s/docs.json"
evdocs-site-url))
(json-read))
(json-read-file file))))
@@ -136,60 +142,47 @@ DOC is a document slug."
(clrhash evdocs--index)
(message "Documentation for `%s' installed." doc)))
-;;; Manipulating a single document
-
-(defvar evdocs--doc-index (make-hash-table))
-
-(defun evdocs--doc-index (doc)
- (or (gethash doc evdocs--doc-index)
- (puthash doc
- (json-read-file (expand-file-name (concat doc "/index.json")
- evdocs-data-dir))
- evdocs--doc-index)))
-
-(defun evdocs--entries (doc)
- "Return a list of entries for document DOC."
- (mapcar (let ((docid (cons 'doc doc)))
- (lambda (entry)
- (let-alist entry
- (cons (concat .type ": " .name) (cons docid entry)))))
- (alist-get 'entries (evdocs--doc-index doc))))
-
-(defvar evdocs--entries (make-hash-table))
-
-(defun evdocs--entries (doc)
- "Return a list of entries for document DOC."
- (or (gethash doc evdocs--entries)
- (puthash doc
- (seq-map-indexed
- (let ((docid (cons 'doc doc)))
- (lambda (entry i)
- (let-alist entry
- (thread-last entry
- (cons `(index . ,i))
- (cons docid)
- (cons .name)))))
- (alist-get 'entries (json-read-file
- (expand-file-name (concat doc
"/index.json")
- evdocs-data-dir))))
- evdocs--entries)))
-
-
-(defun evdocs--read-entry (prompt)
- (let* ((cands (mapcan #'evdocs--entries evdocs-current-docs)))
- (cdr (assoc (completing-read prompt cands nil t) cands))))
+;;; Document indexes
+
+(defvar evdocs--index (make-hash-table :test 'equal)
+ "A hash table to cache document indices.")
+
+(defun evdocs--index (doc)
+ "Return the index of document DOC.
+This is an alist containing `entries' and `types'."
+ (if-let ((idx (gethash doc evdocs--index)))
+ (prog1 idx
+ (timer-set-time (alist-get 'timer idx) evdocs-timeout))
+ (let* ((docid (cons 'doc doc))
+ (idx (json-read-file (expand-file-name (concat doc "/index.json")
+ evdocs-data-dir)))
+ (entries (alist-get 'entries idx)))
+ (setf (alist-get 'timer idx)
+ (run-at-time evdocs-timeout nil
+ (lambda () (remhash doc evdocs--index))))
+ (seq-do-indexed (lambda (entry i)
+ (push `(index . ,i) entry)
+ (push docid entry)
+ (aset entries i entry))
+ entries)
+ (puthash doc idx evdocs--index))))
;;; Documentation viewer
-(defvar-local evdocs--data nil
- "Alist of data, set buffer-locally when in `evdocs-mode'.")
+(defvar-local evdocs--stack nil
+ "List of viewed entries, set buffer-locally when in `evdocs-mode'.")
+
+(defvar-local evdocs--forward-stack nil
+ "List of viewed entries for `evdocs-go-forward'.")
(defvar evdocs-header-line
- '(:eval (let-alist evdocs--data
- (concat (evdocs--doc-title .doc) " » " .type " » " .name))))
+ '(:eval (let-alist (car evdocs--stack)
+ (concat (evdocs--doc-title .doc)
+ evdocs-separator .type
+ evdocs-separator .name))))
(define-derived-mode evdocs-mode special-mode "DevDocs"
- "Mode for displaying DevDocs documents."
+ "Major mode for viewing DevDocs documents."
(setq-local browse-url-browser-function
(cons '("\\`[^:]*\\'" . evdocs--browse-url)
(if (functionp browse-url-browser-function)
@@ -200,14 +193,35 @@ DOC is a document slug."
truncate-lines t))
(defun evdocs-goto-target ()
+ "Go to the original position in a DevDocs buffer."
(interactive)
(goto-char (point-min))
(text-property-search-forward 'shr-target-id)
(beginning-of-line))
+(defun evdocs-go-back ()
+ "Go to the previously displayed entry in this DevDocs buffer."
+ (interactive)
+ (unless (cadr evdocs--stack)
+ (user-error "No previous entry"))
+ (push (pop evdocs--stack) evdocs--forward-stack)
+ (evdocs--render (pop evdocs--stack)))
+
+(defun evdocs-go-forward ()
+ "Go to the next entry in this DevDocs buffer."
+ (interactive)
+ (unless (car evdocs--forward-stack)
+ (user-error "No next entry"))
+ (evdocs--render (pop evdocs--forward-stack)))
+
(let ((map evdocs-mode-map))
(define-key map [tab] 'forward-button)
- (define-key map [backtab] 'backward-button))
+ (define-key map [backtab] 'backward-button)
+ (define-key map "l" 'evdocs-go-back)
+ (define-key map "r" 'evdocs-go-forward)
+ (define-key map "." 'evdocs-goto-target))
+
+;;; Rendering
(defun evdocs--path-file (path)
"Return the non-fragment part of PATH."
@@ -228,13 +242,14 @@ DOC is a document slug."
(defun evdocs--render (entry)
"Render a DevDocs documentation entry, returning a buffer.
-ENTRY is an alist like those returned by `evdocs--entries',
-possibly with an additional ENTRY.fragment which overrides the
-ENTRY.path fragment part."
+ENTRY is an alist like those in `evdocs--index', possibly with an
+additional ENTRY.fragment which overrides the fragment part of
+ENTRY.path."
(or (libxml-available-p)
(error "This function requires Emacs to be compiled with libxml2"))
(with-current-buffer (get-buffer-create "*devdocs*")
- (evdocs-mode)
+ (unless (eq major-mode 'evdocs-mode)
+ (evdocs-mode))
(let-alist entry
(let ((shr-target-id (or .fragment (evdocs--path-fragment .path)))
(buffer-read-only nil)
@@ -248,13 +263,13 @@ ENTRY.path fragment part."
(insert-file-contents file)
(libxml-parse-html-region (point-min) (point-max)))))
(set-buffer-modified-p nil)
- (setq-local evdocs--data entry
- evdocs-current-docs (list .doc))
+ (setq-local evdocs-current-docs (list .doc))
+ (push entry evdocs--stack)
(evdocs-goto-target)
(current-buffer))))
(defun evdocs--browse-url (url &rest _)
- (let-alist evdocs--data
+ (let-alist (car evdocs--stack)
(let* ((dest (evdocs--path-expand url .path))
(file (evdocs--path-file dest))
(frag (evdocs--path-fragment dest))
@@ -263,7 +278,7 @@ ENTRY.path fragment part."
(or (string= .path dest)
(string= .path file)))
it))
- (evdocs--entries .doc))))
+ (alist-get 'entries (evdocs--index .doc)))))
(unless entry (error "Can't find `%s'" dest))
(when frag (push `(fragment . ,frag) entry))
(evdocs--render entry))))
- [elpa] branch externals/devdocs created (now 77f4ace), ELPA Syncer, 2021/05/29
- [elpa] externals/devdocs 2bc4d37 4/7: Improve lookup command, ELPA Syncer, 2021/05/29
- [elpa] externals/devdocs 71142b8 1/7: Initial commit, ELPA Syncer, 2021/05/29
- [elpa] externals/devdocs 15d95ef 2/7: Refine document management, ELPA Syncer, 2021/05/29
- [elpa] externals/devdocs ccadf08 5/7: Add a README, ELPA Syncer, 2021/05/29
- [elpa] externals/devdocs d5c437d 6/7: Rename package, ELPA Syncer, 2021/05/29
- [elpa] externals/devdocs 77f4ace 7/7: Add a devdocs-search command, as in the old devdocs package, ELPA Syncer, 2021/05/29
- [elpa] externals/devdocs 257813d 3/7: Cache document index with timeout,
ELPA Syncer <=