unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#58626: Proposed changes to implement opening URLs on macOS
@ 2022-10-18 22:53 Perry Smith via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-12 20:57 ` Stefan Kangas
  0 siblings, 1 reply; 3+ messages in thread
From: Perry Smith via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-10-18 22:53 UTC (permalink / raw)
  To: 58626

[-- Attachment #1: Type: text/plain, Size: 1912 bytes --]

NOTE: I am subscribed to this list but I do not receive emails from
the list.  Please CC me on replies and updates.  I will also check in
the archive every few days.

My email to the developers list explains better why I did this.[1] The
short version is an exception thrown by my Ruby on Rails app displays
a stack trace with file names and line numbers.  In the past, it was
possible to click on the line and it would pop into Emacs.  This was
after adding in Mitsuharu Yamamoto mods and other effort.  I wanted to
recreate that facility but in such a way that it might be accepted
into the main Emacs development.

It appears macOS uses the scheme in URLs a lot so these changes seem
to fit in with their general designs.

Attached is my patch file based upon the emacs-28.2 tar ball.  With
these changes, I can do:

    open emacs:///some/path/to/file.txt#25,40

and the file opens in Emacs with lines 25-40 highlighted.  Clicking a
link in a browser page with the same href as above causes the same
action.  The fragment can be omitted entirely or can be just a single
line.  The comma can also be a dash or a colon.

(I’m also going to submit a feature request to RoR to leverage this
feature.)

I don’t claim to be a lisp programmer so feel free to clean up what
I’ve done.

Note that the documentation says:

    If your delegate implements this method, AppKit does not call the
    application:openFile: or application:openFiles: methods.

I left the code for openFile and openFiles under an **assumption**
that on macOS before 10.13, openURLs will not be called and the system
will fall back to the openFile and openFiles entry points but I'm not
a macOS programmer either.

Thank you to Daniel Martin.  His reply to my email helped a lot.

Thank you for your time,
Perry
[1] https://lists.gnu.org/archive/html/emacs-devel/2022-10/msg01271.htmlf



[-- Attachment #2: open-url.diff.gz --]
[-- Type: application/x-gzip, Size: 3188 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* bug#58626: Proposed changes to implement opening URLs on macOS
  2022-10-18 22:53 bug#58626: Proposed changes to implement opening URLs on macOS Perry Smith via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-11-12 20:57 ` Stefan Kangas
  2022-11-12 23:36   ` Perry Smith via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 3+ messages in thread
From: Stefan Kangas @ 2022-11-12 20:57 UTC (permalink / raw)
  To: Perry Smith; +Cc: 58626

Perry Smith <pedzsan@icloud.com> writes:

> Attached is my patch file based upon the emacs-28.2 tar ball.  With
> these changes, I can do:
>
>     open emacs:///some/path/to/file.txt#25,40

Could you send the patch in uncompressed instead?  That will simplify
reviewing it.

Thanks.





^ permalink raw reply	[flat|nested] 3+ messages in thread

* bug#58626: Proposed changes to implement opening URLs on macOS
  2022-11-12 20:57 ` Stefan Kangas
@ 2022-11-12 23:36   ` Perry Smith via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 3+ messages in thread
From: Perry Smith via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-12 23:36 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: 58626



> On Nov 12, 2022, at 14:57, Stefan Kangas <stefankangas@gmail.com> wrote:
> 
> Perry Smith <pedzsan@icloud.com> writes:
> 
>> Attached is my patch file based upon the emacs-28.2 tar ball.  With
>> these changes, I can do:
>> 
>>    open emacs:///some/path/to/file.txt#25,40
> 
> Could you send the patch in uncompressed instead?  That will simplify
> reviewing it.

Please let me know if this doesn’t work...

Only in emacs-28.2-new: .DS_Store
Only in emacs-28.2-new: What-I-Did.txt
Only in emacs-28.2/admin/unidata: unidata-gen.elc
Only in emacs-28.2/admin/unidata: unidata.txt
Only in emacs-28.2/admin/unidata: uvs.elc
Only in emacs-28.2-new/lib: sys
Only in emacs-28.2-new/lib-src: ctags.dSYM
Only in emacs-28.2-new/lib-src: ebrowse.dSYM
Only in emacs-28.2-new/lib-src: emacsclient.dSYM
Only in emacs-28.2-new/lib-src: etags.dSYM
Only in emacs-28.2-new/lib-src: hexl.dSYM
Only in emacs-28.2-new/lib-src: make-docfile.dSYM
Only in emacs-28.2-new/lib-src: make-fingerprint.dSYM
Only in emacs-28.2-new/lib-src: movemail.dSYM
Only in emacs-28.2/lisp: loaddefs.el
Only in emacs-28.2-new/lisp: loaddefs.el~
diff -rc emacs-28.2/lisp/term/common-win.el emacs-28.2-new/lisp/term/common-win.el
*** emacs-28.2/lisp/term/common-win.el 2022-09-06 16:31:54.000000000 -0500
--- emacs-28.2-new/lisp/term/common-win.el 2022-10-16 07:53:34.000000000 -0500
***************
*** 73,78 ****
--- 73,79 ----
        (cons 12 'ns-new-frame)
        (cons 13 'ns-toggle-toolbar)
        (cons 14 'ns-show-prefs)
+       (cons 15 'ns-open-url)
        ))))
      (set-terminal-parameter frame 'x-setup-function-keys t)))
  Binary files emacs-28.2/lisp/term/common-win.elc and emacs-28.2-new/lisp/term/common-win.elc differ
diff -rc emacs-28.2/lisp/term/ns-win.el emacs-28.2-new/lisp/term/ns-win.el
*** emacs-28.2/lisp/term/ns-win.el 2022-09-06 16:31:54.000000000 -0500
--- emacs-28.2-new/lisp/term/ns-win.el 2022-10-18 11:36:44.000000000 -0500
***************
*** 182,187 ****
--- 182,188 ----
  (define-key global-map [ns-new-frame] 'make-frame)
  (define-key global-map [ns-toggle-toolbar] 'ns-toggle-toolbar)
  (define-key global-map [ns-show-prefs] 'customize)
+ (define-key global-map [ns-open-url] 'ns-open-url)
      ;; Set up a number of aliases and other layers to pretend we're using
***************
*** 530,535 ****
--- 531,578 ----
    (global-set-key [drag-n-drop] 'ns-drag-n-drop)
  + (defvar ns-input-url-scheme)            ; nsterm.m
+ (defvar ns-input-url-user)              ; nsterm.m
+ (defvar ns-input-url-password)          ; nsterm.m
+ (defvar ns-input-url-host)              ; nsterm.m
+ (defvar ns-input-url-port)              ; nsterm.m
+ (defvar ns-input-url-path)              ; nsterm.m
+ (defvar ns-input-url-query)             ; nsterm.m
+ (defvar ns-input-url-fragment)          ; nsterm.m
+ 
+ (defun ns-open-url ()
+   "Open a buffer as directed by the URL which has been broken down
+   into components:
+     `ns-input-url-scheme'   - the URL's scheme   (string)
+     `ns-input-url-user'     - the URL's user     (string)
+     `ns-input-url-password' - the URL's password (string)
+     `ns-input-url-host'     - the URL's host     (string)
+     `ns-input-url-port'     - the URL's port     (integer)
+     `ns-input-url-path'     - the URL's path     (string)
+     `ns-input-url-query'    - the URL's query    (string)
+     `ns-input-url-fragment' - the URL's fragment (string)
+ "
+   (interactive)
+   (cond
+    ((equal ns-input-url-scheme "file")
+     (progn (setq ns-input-file (append (list ns-input-url-path)))
+            (setq ns-input-line nil)     ; My testing on macOS 12.6 shows the fragment is never passed
+            (ns-open-file-select-line)))
+    ((equal ns-input-url-scheme "emacs")
+     (progn (setq ns-input-file (append (list ns-input-url-path)))
+            (setq ns-input-line
+                  (and ns-input-url-fragment
+                       (let ((seq (mapcar #'string-to-number (split-string ns-input-url-fragment "[-,:]" t))))
+                         (cond
+                          ((= (length seq) 1) (car seq))
+                          ((= (length seq) 2) (cons (car seq) (car (cdr seq))))))))
+            (ns-open-file-select-line)))
+    (t (message (format "scheme: %s; user: %s; password: %s; host: %s; port: %d; path: %s; query: %s; fragment: %s"
+                        ns-input-url-scheme ns-input-url-user
+                        ns-input-url-password ns-input-url-host
+                        ns-input-url-port ns-input-url-path
+                        ns-input-url-query ns-input-url-fragment)))))
+ 
  ;;;; Frame-related functions.
    ;; nsterm.m
Binary files emacs-28.2/lisp/term/ns-win.elc and emacs-28.2-new/lisp/term/ns-win.elc differ
Only in emacs-28.2-new/nextstep: .DS_Store
Only in emacs-28.2-new/nextstep/Cocoa/Emacs.base/Contents/Resources: English.lproj
diff -rc emacs-28.2/nextstep/templates/Info.plist.in emacs-28.2-new/nextstep/templates/Info.plist.in
*** emacs-28.2/nextstep/templates/Info.plist.in 2022-09-06 16:31:54.000000000 -0500
--- emacs-28.2-new/nextstep/templates/Info.plist.in 2022-10-15 11:31:41.000000000 -0500
***************
*** 672,677 ****
--- 672,687 ----
  <string>mailto</string>
  </array>
  </dict>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleURLName</key>
+ <string>Emacs Local Address URL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>emacs</string>
+ </array>
+ </dict>
  </array>
  <key>NSAppleScriptEnabled</key>
  <string>YES</string>
Only in emacs-28.2-new/nextstep/templates: Info.plist.in-orig
diff -rc emacs-28.2/src/nsterm.m emacs-28.2-new/src/nsterm.m
*** emacs-28.2/src/nsterm.m 2022-09-06 16:31:54.000000000 -0500
--- emacs-28.2-new/src/nsterm.m 2022-10-16 12:13:33.000000000 -0500
***************
*** 292,298 ****
  static struct input_event *q_event_ptr = NULL;
  static int n_emacs_events_pending = 0;
  static NSMutableArray *ns_pending_files, *ns_pending_service_names,
!   *ns_pending_service_args;
  static BOOL ns_do_open_file = NO;
  static BOOL ns_last_use_native_fullscreen;
  --- 292,298 ----
  static struct input_event *q_event_ptr = NULL;
  static int n_emacs_events_pending = 0;
  static NSMutableArray *ns_pending_files, *ns_pending_service_names,
!   *ns_pending_service_args, *ns_pending_urls;
  static BOOL ns_do_open_file = NO;
  static BOOL ns_last_use_native_fullscreen;
  ***************
*** 4361,4366 ****
--- 4361,4372 ----
            [ns_pending_service_names removeObjectAtIndex: 0];
            [ns_pending_service_args removeObjectAtIndex: 0];
          }
+       /* Process the open URL requests */
+       else if (ns_pending_urls && [ns_pending_urls count] != 0
+                && [(EmacsApp *) NSApp openURL: [ns_pending_urls objectAtIndex: 0]])
+         {
+             [ns_pending_urls removeObjectAtIndex: 0];
+         }
        else
          {
            /* Run and wait for events.  We must always send one NX_APPDEFINED event
***************
*** 5123,5128 ****
--- 5129,5135 ----
    ns_pending_files = [[NSMutableArray alloc] init];
    ns_pending_service_names = [[NSMutableArray alloc] init];
    ns_pending_service_args = [[NSMutableArray alloc] init];
+   ns_pending_urls = [[NSMutableArray alloc] init];
      /* Start app and create the main menu, window, view.
       Needs to be here because ns_initialize_display_info () uses AppKit classes.
***************
*** 5938,5943 ****
--- 5945,6004 ----
    /* ==========================================================================
  +     Open URL
+ 
+    ========================================================================== */
+ 
+ /* Open a URL after going into queue read by ns_read_socket.  */
+ - (BOOL) openURL: (NSURL *)url
+ {
+   NSTRACE ("[EmacsApp openURL:]");
+ 
+   struct frame *emacsframe = SELECTED_FRAME ();
+   NSEvent *theEvent = [NSApp currentEvent];
+ 
+   if (!emacs_event)
+     return NO;
+ 
+   emacs_event->kind = NS_NONKEY_EVENT;
+   emacs_event->code = KEY_NS_OPEN_URL;
+   ns_input_url_scheme   = [[url scheme]   lispString];
+   ns_input_url_user     = [[url user]     lispString];
+   ns_input_url_password = [[url password] lispString];
+   ns_input_url_host     = [[url host]     lispString];
+   ns_input_url_port     = make_int([[url port] intValue]);
+   ns_input_url_path     = [[url path]     lispString];
+   ns_input_url_query    = [[url query]    lispString];
+   ns_input_url_fragment = [[url fragment] lispString];
+   EV_TRAILER (theEvent);
+ 
+   return YES;
+ }
+ 
+ /* Notification from the Workspace to open a URL.  */
+ - (void)application: sender openURLs: (NSArray<NSURL *> *)urlList
+ {
+   NSEnumerator *urls = [urlList objectEnumerator];
+   NSURL *url;
+ 
+   NSTRACE ("[EmacsApp openURLs:]");
+   while ((url = [urls nextObject]) != nil)
+     if (ns_do_open_file || not_in_argv ([url path])) {
+       [ns_pending_urls addObject: url];
+     }
+ 
+   /* The documentation says to do this for openFiles but it is not
+    * mentioned in the openURLs doc so I'm going to leave it out for
+    * now.
+    
+   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
+    */
+ 
+ }
+ 
+ 
+ /* ==========================================================================
+ 
      Service provision
       ========================================================================== */
***************
*** 7004,7010 ****
    height = (int)NSHeight (frame);
      NSTRACE_SIZE ("New size", NSMakeSize (width, height));
!   NSTRACE_SIZE ("Original size", size);
      /* Reset the frame size to match the bounds of the superview (the
       NSWindow's contentView).  We need to do this as sometimes the
--- 7065,7071 ----
    height = (int)NSHeight (frame);
      NSTRACE_SIZE ("New size", NSMakeSize (width, height));
!   NSTRACE_SIZE ("Original size", oldSize);
      /* Reset the frame size to match the bounds of the superview (the
       NSWindow's contentView).  We need to do this as sometimes the
***************
*** 9845,9850 ****
--- 9906,9947 ----
                "The file specified in the last NS event.");
    ns_input_file =Qnil;
  +   /* -- URL components */
+ 
+   DEFVAR_LISP ("ns-input-url-scheme", ns_input_url_scheme,
+                "The scheme component of the URL specified in the last NS event.");
+   ns_input_url_scheme =Qnil;
+ 
+   DEFVAR_LISP ("ns-input-url-user", ns_input_url_user,
+                "The user component of the URL specified in the last NS event.");
+   ns_input_url_user =Qnil;
+ 
+   DEFVAR_LISP ("ns-input-url-password", ns_input_url_password,
+                "The password component of the URL specified in the last NS event.");
+   ns_input_url_password =Qnil;
+ 
+   DEFVAR_LISP ("ns-input-url-host", ns_input_url_host,
+                "The host component of the URL specified in the last NS event.");
+   ns_input_url_host =Qnil;
+ 
+   DEFVAR_LISP ("ns-input-url-port", ns_input_url_port,
+                "The port component of the URL specified in the last NS event.");
+   ns_input_url_port =Qnil;
+ 
+   DEFVAR_LISP ("ns-input-url-path", ns_input_url_path,
+                "The path component of the URL specified in the last NS event.");
+   ns_input_url_path =Qnil;
+ 
+   DEFVAR_LISP ("ns-input-url-query", ns_input_url_query,
+                "The query component of the URL specified in the last NS event.");
+   ns_input_url_query =Qnil;
+ 
+   DEFVAR_LISP ("ns-input-url-fragment", ns_input_url_fragment,
+                "The fragment component of the URL specified in the last NS event.");
+   ns_input_url_fragment =Qnil;
+ 
+   /* -- */
+ 
    DEFVAR_LISP ("ns-working-text", ns_working_text,
                "String for visualizing working composition sequence.");
    ns_working_text =Qnil;
Only in emacs-28.2-new: trace







^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-11-12 23:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-18 22:53 bug#58626: Proposed changes to implement opening URLs on macOS Perry Smith via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-11-12 20:57 ` Stefan Kangas
2022-11-12 23:36   ` Perry Smith via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).