branch: externals/osm
commit 1aaa8bc5f41bbfe37f67a6658b7d784b7719c3c4
Author: Daniel Mendler <[email protected]>
Commit: Daniel Mendler <[email protected]>
Add osm-url command which handles geo urls and Google Maps urls
---
CHANGELOG.org | 5 ++++
README.org | 2 +-
osm.el | 85 ++++++++++++++++++++++++++++++++++++++++++-----------------
3 files changed, 67 insertions(+), 25 deletions(-)
diff --git a/CHANGELOG.org b/CHANGELOG.org
index ad766d3379..538d1c702c 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -2,6 +2,11 @@
#+author: Daniel Mendler
#+language: en
+* Development
+
+- New command =osm-url= which handles Geo and Google Maps URLs.
+- Register =osm-url= for both ~geo:~ and Google Maps URLs.
+
* Version 1.10 (2025-11-30)
- Disable ~mouse-shift-adjust-mode~ locally.
diff --git a/README.org b/README.org
index b0284ecb40..4a7bd9c9bc 100644
--- a/README.org
+++ b/README.org
@@ -100,7 +100,6 @@ e.g., ~C-c o~. The format of the links complies with the
[[https://en.wikipedia.
[[geo:51.48950698022105,-0.144195556640625;z=11][London, England, 51.49°
-0.14°]]
[[geo:55.686875255964424,12.569732666015625;z=12;s=cyclosm][København,
Danmark, 55.69° 12.57° CyclOSM]]
[[geo:27.961656050984658,86.89224243164062;z=13;s=opentopomap][Mount
Everest, 27.96° 86.89° OpenTopoMap]]
- <geo:Tour Eiffel, Av. Gustave Eiffel, Paris> (Address link)
#+end_example
**** Elisp link examples
@@ -136,6 +135,7 @@ initiate a search.
- ~h~: =osm-home= - Open new map at home coordinates
- ~s~: =osm-search= - Search and jump to location
- ~t~: =osm-goto= - Go to coordinates
+- ~u~: =osm-url= - Go to Geo URL.
- ~v~: =osm-server= - Select server
- ~j~: =osm-jump= - Jump to pin (bookmark or POI)
- ~x~: =osm-gpx-show= - Show GPX file in map viewer
diff --git a/osm.el b/osm.el
index e0e9df55df..3097325ecd 100644
--- a/osm.el
+++ b/osm.el
@@ -263,6 +263,7 @@ Should be at least 7 days according to the server usage
policies."
"s" #'osm-search
"v" #'osm-server
"t" #'osm-goto
+ "u" #'osm-url
"j" #'osm-jump
"x" #'osm-gpx-show
"X" #'osm-gpx-hide)
@@ -332,12 +333,13 @@ Should be at least 7 days according to the server usage
policies."
["Go home" osm-home]
["Center" osm-center]
["Go to coordinates" osm-goto]
+ ["Go to URL" osm-url]
["Jump to pin" osm-jump]
["Search by name" osm-search]
["Change tile server" osm-server]
"--"
["Org Link" org-store-link]
- ["Geo Url" osm-save-url]
+ ["Geo URL" osm-save-url]
["Elisp Link" (osm-save-url t)]
("Bookmark"
["Set" osm-bookmark-set]
@@ -1417,6 +1419,33 @@ Print NAME if not QUIET."
(osm--goto lat lon zoom nil 'osm-selected nil)
nil)
+;;;###autoload
+(defun osm-url (url &rest _)
+ "Go to Geo or Google Maps URL.
+See also `osm-save-url'."
+ (interactive "sGeo URL: ")
+ (cond
+ ((string-match
+
"\\`geo:\\([0-9.-]+\\),\\([0-9.-]+\\)\\(?:,[0-9.-]+\\)?\\(;.+\\'\\|\\'\\)" url)
+ (let* ((lat (string-to-number (match-string 1 url)))
+ (lon (string-to-number (match-string 2 url)))
+ (args (url-parse-args (match-string 3 url) ""))
+ (zoom (cdr (assoc "z" args)))
+ (server (cdr (assoc "s" args))))
+ (osm--goto lat lon
+ (and zoom (string-to-number zoom))
+ (and server (intern-soft server))
+ 'osm-selected "Geo Link")))
+ ((string-match "goo.*@\\([0-9.-]+\\),\\([0-9.-]+\\),\\([0-9]+\\)" url)
+ (let ((lat (string-to-number (match-string 1 url)))
+ (lon (string-to-number (match-string 2 url)))
+ (zoom (string-to-number (match-string 3 url))))
+ (osm--goto lat lon zoom nil 'osm-selected "Geo Link")))
+ ((string-match-p "\\`https?://.*\\(goo.*maps\\|maps.*goo\\)" url)
+ (osm-url (string-remove-prefix "http" (osm--get-redirect url))))
+ (t
+ (user-error "Invalid URL"))))
+
;;;###autoload
(defun osm (&rest link)
"Go to LINK.
@@ -1429,24 +1458,15 @@ When called interactively, call the function
`osm-home'."
(setq server (car server))
(unless (and server (symbolp server)) (setq server nil)) ;; Ignore comment
(osm--goto lat lon zoom server 'osm-selected "Elisp Link"))
- ((and `(,url . ,_) (guard (stringp url)))
- (if (string-match
-
"\\`geo:\\([0-9.-]+\\),\\([0-9.-]+\\)\\(?:,[0-9.-]+\\)?\\(;.+\\'\\|\\'\\)" url)
- (let* ((lat (string-to-number (match-string 1 url)))
- (lon (string-to-number (match-string 2 url)))
- (args (url-parse-args (match-string 3 url) ""))
- (zoom (cdr (assoc "z" args)))
- (server (cdr (assoc "s" args))))
- (osm--goto lat lon
- (and zoom (string-to-number zoom))
- (and server (intern-soft server))
- 'osm-selected "Geo Link"))
- (osm-search (string-remove-prefix "geo:" url))))
- (_ (error "Invalid osm link"))))
+ ((and `(,str) (guard (stringp str)))
+ (if (string-match-p "\\`\\(geo:\\|https?://\\)" str)
+ (osm-url str)
+ (osm-search str)))
+ (_ (error "Invalid Osm link"))))
;;;###autoload
(defun osm-bookmark-jump (bm)
- "Jump to osm bookmark BM."
+ "Jump to Osm bookmark BM."
(interactive (list (osm--bookmark-read)))
(pcase-let ((`(,lat ,lon ,zoom) (bookmark-prop-get bm 'coordinates)))
(set-buffer (osm--goto lat lon zoom
@@ -1456,7 +1476,7 @@ When called interactively, call the function `osm-home'."
;;;###autoload
(defun osm-bookmark-delete (bm)
- "Delete osm bookmark BM."
+ "Delete Osm bookmark BM."
(interactive (list (osm--bookmark-read)))
(when (y-or-n-p (format "Delete bookmark `%s'? " bm))
(bookmark-delete bm)
@@ -1465,7 +1485,7 @@ When called interactively, call the function `osm-home'."
;;;###autoload
(defun osm-bookmark-rename (old-name)
- "Rename osm bookmark OLD-NAME."
+ "Rename Osm bookmark OLD-NAME."
(interactive (list (car (osm--bookmark-read))))
(let ((new-name (read-from-minibuffer "New name: " old-name nil nil
'bookmark-history old-name)))
@@ -1490,7 +1510,7 @@ When called interactively, call the function `osm-home'."
(error "No bookmark selected")))
(defun osm-bookmark-set ()
- "Create osm bookmark."
+ "Create Osm bookmark."
(interactive nil osm-mode)
(osm--barf-unless-osm)
(unwind-protect
@@ -1608,11 +1628,11 @@ When called interactively, call the function
`osm-home'."
(sort index (lambda (x y) (string< (car x) (car y))))))
(defun osm--imenu-goto (_name pos)
- "Goto Imenu POS."
+ "Go to Imenu POS."
(osm--goto (aref pos 0) (aref pos 1) (aref pos 2) nil nil nil))
(defun osm--fetch-json (url)
- "Get json from URL."
+ "Get JSON from URL."
(osm--check-libraries)
(with-temp-buffer
(let* ((default-process-coding-system '(utf-8-unix . utf-8-unix))
@@ -1623,6 +1643,21 @@ When called interactively, call the function `osm-home'."
(goto-char (point-min))
(json-parse-buffer :array-type 'list :object-type 'alist)))
+(defun osm--get-redirect (url)
+ "Get redirect location from URL."
+ (osm--check-libraries)
+ (with-temp-buffer
+ (let* ((default-process-coding-system '(utf-8-unix . utf-8-unix))
+ (status (apply #'call-process "curl" nil (current-buffer) nil
+ `(,@(split-string-and-unquote osm-curl-options)
+ "-I" "--no-location" ,url))))
+ (unless (eq status 0)
+ (error "Fetching %s exited with status %s" url status)))
+ (goto-char (point-min))
+ (if (re-search-forward "location: \\([^\n]+\\)" nil t)
+ (match-string 1)
+ (error "Invalid redirect %s" url))))
+
(defun osm--search (needle)
"Globally search for NEEDLE and return the list of results."
(message "Contacting %s" osm-search-server)
@@ -1800,8 +1835,8 @@ See `osm-search-server' and `osm-search-language' for
customization."
(osm--goto nil nil nil server nil nil))
(defun osm-save-url (&optional arg)
- "Save coordinates as url in the kill ring.
-If prefix ARG is given, store url as Elisp expression."
+ "Save coordinates as URL in the kill ring.
+If prefix ARG is given, store URL as Elisp expression."
(interactive "P" osm-mode)
(osm--barf-unless-osm)
(pcase-let* ((`(,lat ,lon ,loc) (osm--fetch-location-data "New Link"))
@@ -1837,7 +1872,9 @@ The properties are checked as keyword arguments. See
nil)
;;;###autoload
-(add-to-list 'browse-url-default-handlers '("\\`geo:" . osm))
+(progn
+ (add-to-list 'browse-url-default-handlers '("\\`geo:" . osm-url))
+ (add-to-list 'browse-url-default-handlers
'("\\`https?://.*\\(goo.*maps\\|maps.*goo\\)" . osm-url)))
;;;###autoload
(eval-after-load 'ol