diff options
| author | Noam Postavsky | 2017-01-08 18:19:32 -0500 |
|---|---|---|
| committer | Noam Postavsky | 2017-01-15 13:04:54 -0500 |
| commit | fd6b829d91da73a945643b5916ee6d79c992e030 (patch) | |
| tree | 5759b3099ad52bdf3fb80948a12973d349981b2f | |
| parent | af3db69ee640d9a1e9027c04ba3b5bec7c2681ab (diff) | |
| download | emacs-fd6b829d91da73a945643b5916ee6d79c992e030.tar.gz emacs-fd6b829d91da73a945643b5916ee6d79c992e030.zip | |
Improve ffap-gopher-at-point handling of long lines
* lisp/ffap.el (ffap-gopher-regexp): Only match the KEY part. Note
setting to nil is now supported.
(ffap--gopher-var-on-line): New function.
(ffap-gopher-at-point): Use it instead of the old ffap-gopher-regexp
which could overflow the regexp stack on long lines (Bug#25391). Use
`let-alist' instead of calling `set' on local variables.
* test/lisp/ffap-tests.el (ffap-gopher-at-point): New test.
| -rw-r--r-- | lisp/ffap.el | 66 | ||||
| -rw-r--r-- | test/lisp/ffap-tests.el | 17 |
2 files changed, 52 insertions, 31 deletions
diff --git a/lisp/ffap.el b/lisp/ffap.el index 8144d41f3a1..068897b21b8 100644 --- a/lisp/ffap.el +++ b/lisp/ffap.el | |||
| @@ -76,6 +76,7 @@ | |||
| 76 | ;; (setq ffap-machine-p-known 'accept) ; no pinging | 76 | ;; (setq ffap-machine-p-known 'accept) ; no pinging |
| 77 | ;; (setq ffap-url-regexp nil) ; disable URL features in ffap | 77 | ;; (setq ffap-url-regexp nil) ; disable URL features in ffap |
| 78 | ;; (setq ffap-shell-prompt-regexp nil) ; disable shell prompt stripping | 78 | ;; (setq ffap-shell-prompt-regexp nil) ; disable shell prompt stripping |
| 79 | ;; (setq ffap-gopher-regexp nil) ; disable gopher bookmark matching | ||
| 79 | ;; | 80 | ;; |
| 80 | ;; ffap uses `browse-url' (if found, else `w3-fetch') to fetch URL's. | 81 | ;; ffap uses `browse-url' (if found, else `w3-fetch') to fetch URL's. |
| 81 | ;; For a hairier `ffap-url-fetcher', try ffap-url.el (same ftp site). | 82 | ;; For a hairier `ffap-url-fetcher', try ffap-url.el (same ftp site). |
| @@ -1194,43 +1195,46 @@ Sets the variable `ffap-string-at-point-region' to the bounds of URL, if any." | |||
| 1194 | val)))) | 1195 | val)))) |
| 1195 | 1196 | ||
| 1196 | (defvar ffap-gopher-regexp | 1197 | (defvar ffap-gopher-regexp |
| 1197 | "^.*\\<\\(Type\\|Name\\|Path\\|Host\\|Port\\) *= *\\(.*\\) *$" | 1198 | "\\<\\(Type\\|Name\\|Path\\|Host\\|Port\\) *= *" |
| 1198 | "Regexp matching a line in a gopher bookmark (maybe indented). | 1199 | "Regexp matching a key in a gopher bookmark. |
| 1199 | The two subexpressions are the KEY and VALUE.") | 1200 | Set to nil to disable matching gopher bookmarks.") |
| 1201 | |||
| 1202 | (defun ffap--gopher-var-on-line () | ||
| 1203 | "Return (KEY . VALUE) of gopher bookmark on current line." | ||
| 1204 | (save-excursion | ||
| 1205 | (let ((eol (progn (end-of-line) (skip-chars-backward " ") (point))) | ||
| 1206 | (bol (progn (beginning-of-line) (point)))) | ||
| 1207 | (when (re-search-forward ffap-gopher-regexp eol t) | ||
| 1208 | (let ((key (match-string 1)) | ||
| 1209 | (val (buffer-substring-no-properties (match-end 0) eol))) | ||
| 1210 | (cons (intern (downcase key)) val)))))) | ||
| 1200 | 1211 | ||
| 1201 | (defun ffap-gopher-at-point () | 1212 | (defun ffap-gopher-at-point () |
| 1202 | "If point is inside a gopher bookmark block, return its URL. | 1213 | "If point is inside a gopher bookmark block, return its URL. |
| 1203 | 1214 | ||
| 1204 | Sets the variable `ffap-string-at-point-region' to the bounds of URL, if any." | 1215 | Sets the variable `ffap-string-at-point-region' to the bounds of URL, if any." |
| 1205 | ;; `gopher-parse-bookmark' from gopher.el is not so robust | 1216 | ;; `gopher-parse-bookmark' from gopher.el is not so robust |
| 1206 | (save-excursion | 1217 | (when (stringp ffap-gopher-regexp) |
| 1207 | (beginning-of-line) | 1218 | (save-excursion |
| 1208 | (if (looking-at ffap-gopher-regexp) | 1219 | (let* ((beg (progn (beginning-of-line) |
| 1209 | (progn | 1220 | (while (and (not (bobp)) (ffap--gopher-var-on-line)) |
| 1210 | (while (and (looking-at ffap-gopher-regexp) (not (bobp))) | 1221 | (forward-line -1)) |
| 1211 | (forward-line -1)) | 1222 | (point))) |
| 1212 | (or (looking-at ffap-gopher-regexp) (forward-line 1)) | 1223 | (bookmark (cl-loop for keyval = (ffap--gopher-var-on-line) |
| 1213 | (setq ffap-string-at-point-region (list (point) (point))) | 1224 | while keyval collect keyval |
| 1214 | (let ((type "1") path host (port "70")) | 1225 | do (forward-line 1)))) |
| 1215 | (while (looking-at ffap-gopher-regexp) | 1226 | (when bookmark |
| 1216 | (let ((var (intern | 1227 | (setq ffap-string-at-point-region (list beg (point))) |
| 1217 | (downcase | 1228 | (let-alist (nconc bookmark '((type . "1") (port . "70"))) |
| 1218 | (buffer-substring (match-beginning 1) | 1229 | (if (and .path (string-match "\\`ftp:.*@" .path)) |
| 1219 | (match-end 1))))) | 1230 | (concat "ftp://" |
| 1220 | (val (buffer-substring (match-beginning 2) | 1231 | (substring .path 4 (1- (match-end 0))) |
| 1221 | (match-end 2)))) | 1232 | (substring .path (match-end 0))) |
| 1222 | (set var val) | 1233 | (and (= (length .type) 1) |
| 1223 | (forward-line 1))) | 1234 | .host ;; (ffap-machine-p host) |
| 1224 | (setcdr ffap-string-at-point-region (list (point))) | 1235 | (concat "gopher://" .host |
| 1225 | (if (and path (string-match "^ftp:.*@" path)) | 1236 | (if (equal .port "70") "" (concat ":" .port)) |
| 1226 | (concat "ftp://" | 1237 | "/" .type .path))))))))) |
| 1227 | (substring path 4 (1- (match-end 0))) | ||
| 1228 | (substring path (match-end 0))) | ||
| 1229 | (and (= (length type) 1) | ||
| 1230 | host;; (ffap-machine-p host) | ||
| 1231 | (concat "gopher://" host | ||
| 1232 | (if (equal port "70") "" (concat ":" port)) | ||
| 1233 | "/" type path)))))))) | ||
| 1234 | 1238 | ||
| 1235 | (defvar ffap-ftp-sans-slash-regexp | 1239 | (defvar ffap-ftp-sans-slash-regexp |
| 1236 | (and | 1240 | (and |
diff --git a/test/lisp/ffap-tests.el b/test/lisp/ffap-tests.el index 1ba5f86a887..a3fe3502461 100644 --- a/test/lisp/ffap-tests.el +++ b/test/lisp/ffap-tests.el | |||
| @@ -49,6 +49,23 @@ index 3d7cebadcf..ad4b70d737 100644 | |||
| 49 | (should (equal '(1 1) ffap-string-at-point-region))))) | 49 | (should (equal '(1 1) ffap-string-at-point-region))))) |
| 50 | (and (file-exists-p file) (delete-file file))))) | 50 | (and (file-exists-p file) (delete-file file))))) |
| 51 | 51 | ||
| 52 | (ert-deftest ffap-gopher-at-point () | ||
| 53 | (with-temp-buffer | ||
| 54 | (insert "\ | ||
| 55 | Type = 1 | ||
| 56 | Name = foo | ||
| 57 | Path = /the/path | ||
| 58 | Port = 7070 | ||
| 59 | Host = example.com\n") | ||
| 60 | (should-not (ffap-gopher-at-point)) | ||
| 61 | (goto-char (point-min)) | ||
| 62 | (should (equal (ffap-gopher-at-point) | ||
| 63 | "gopher://example.com:7070/1/the/path")) | ||
| 64 | (should (equal ffap-string-at-point-region | ||
| 65 | (list (point-min) (point-max)))) | ||
| 66 | (let ((ffap-gopher-regexp nil)) | ||
| 67 | (should-not (ffap-gopher-at-point))))) | ||
| 68 | |||
| 52 | (provide 'ffap-tests) | 69 | (provide 'ffap-tests) |
| 53 | 70 | ||
| 54 | ;;; ffap-tests.el ends here | 71 | ;;; ffap-tests.el ends here |