Pro Yearly is on sale from $80 to $50! »

Emacs × Touch Bar

53e469a19bcb4584c87789d237128ca0?s=47 matuyuji
November 17, 2018

Emacs × Touch Bar

Macbook ProのTouch BarからElispの関数を呼べるようにしたのでその実装を紹介しています。
I introduced that the modified version of Emacs which enables to call Elisp functions from Touch Bar.

53e469a19bcb4584c87789d237128ca0?s=128

matuyuji

November 17, 2018
Tweet

Transcript

  1. Emacs × Touch Bar 2018.11.16 ୈ80ճ Cocoaษڧձؔ੢ @matuyuji

  2. @matuyuji • https://github.com/safx • http://safx-dev.blogspot.com • גࣜձࣾψʔϥϘ

  3. None
  4. ΍ͬͨ͜ͱ

  5. None
  6. Motivation • Touch BarʹͳͬͯEsc͕ԡͮ͠Β͘ͳͬͨ • EmacsͰEscΛ࢖͏ͷ͸࣍ͷ3ͭɻ͜ΕΛָʹ࢖͍͍ͨ • ESC-x (M-xʹͳΔ) •

    ESC-% (query-replace) • ESC-& (query-replace-regexpʹׂΓ౰͍ͯͯΔ) • Touch Bar͕͋Δ͔ΒͦΕʹׂΓ౰ͯΒΕͨΒΑ͍?
  7. Agenda • Emacs • Touch Bar • Emacs-mac • Emacs

    × Touch Bar
  8. Emacs

  9. None
  10. How to compile Emacs Requirements • autoconf • automake git

    clone git://git.savannah.gnu.org/emacs.git cd emacs-mac ./autogen.sh ./configure --with-ns --without-makeinfo --without-xpm \ --without-jpeg --without-tiff --without-gif --without-png \ --without-rsvg --without-lcms2 --without-libsystemd \ --without-xml2 --without-imagemagick make cd nextstep # ͜͜ʹEmacs.app͕͋Δ mac OS 10.13.6, Xcode 10.1 (Build version 10B61)
  11. Touch Bar

  12. https://www.apple.com/macbook-pro/

  13. Touch Bar • Late-2016 ͷMacbook ProΑΓ౥ࡌ • ϚϧνλονՄೳͳOLED

  14. Emacs Mac Port

  15. Emacs Mac Port • macOS޲͚ύον෇͖ͷEmacs
 - ઍ༿େֶͷࢁຊޫ੖ઌੜ͕ϝϯς͍ͯ͠Δ • https://bitbucket.org/mituharu/emacs-mac •

    https://github.com/railwaycat/homebrew-emacsmacport • Touch Bar޲͚ͷ࣮૷͕ͪΐͬͱೖ͍ͬͯΔ
  16. How to compile Emacs-Mac git clone https://bitbucket.org/mituharu/emacs-mac.git cd emacs-mac ./autogen.sh

    CC="clang -fobjc-arc" ./configure --without-makeinfo \ --without-xpm --without-jpeg --without-tiff \ --without-gif --without-png --without-rsvg \ --without-lcms2 --without-libsystemd --without-xml2 \ --without-imagemagick make cd mac # ͜͜ʹEmacs.app͕͋Δ
  17. Xcode Touch Bar Simulator λονόʔ͕ͳ͍Ϟσϧʹ΋࢖͑Δ

  18. None
  19. ×

  20. ٙ໰ • Ͳ͏΍ͬͨΒTouch BarʹϘλϯΛදࣔͤ͞ΒΕΔ͔?
 → Ϙλϯͷදࣔ • Ͳ͏΍ͬͨΒTouch BarͷϘλϯΛԡͨ͠ͱ͖ʹLispͷؔ ਺Λ࣮ߦͤ͞ΒΕΔ͔?

    → Ϙλϯͷ࣮ߦ
  21. දࣔ

  22. αϯϓϧΞϓϦ Appleެࣜͷ΋ͷ • NSTouchBar Catalog • ToolbarSample

  23. None
  24. AppleͷαϯϓϧΞϓϦ͸ετʔϦʔϘʔυΛ࢖͍ͬͯΔ → ࠓճͷࢀߟʹͳΒͳ͍

  25. // EmacsMainView - (NSTouchBar *)makeTouchBar { NSTouchBar *mainBar = [[NS_TOUCH_BAR

    alloc] init]; mainBar.delegate = self; mainBar.defaultItemIdentifiers = [NSArray arrayWithObjects:NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER, NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST, nil]; return MRC_AUTORELEASE (mainBar); } - (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { NSTouchBarItem *result = nil; if ([identifier isEqualToString:NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST]) { if (candidateListTouchBarItem == nil) candidateListTouchBarItem = [[NS_CANDIDATE_LIST_TOUCH_BAR_ITEM alloc] initWithIdentifier:NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST]; result = candidateListTouchBarItem; } return result; } NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST
  26. NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101300 #define NS_TOUCH_BAR NSTouchBar #define

    NS_CUSTOM_TOUCH_BAR_ITEM NSCustomTouchBarItem #define NS_CANDIDATE_LIST_TOUCH_BAR_ITEM NSCandidateListTouchBarItem #define NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER \ NSTouchBarItemIdentifierCharacterPicker #define NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST \ NSTouchBarItemIdentifierCandidateList #else #define NS_TOUCH_BAR (NSClassFromString (@"NSTouchBar")) #define NS_CUSTOM_TOUCH_BAR_ITEM (NSClassFromString (@"NSCustomTouchBarItem")) #define NS_CANDIDATE_LIST_TOUCH_BAR_ITEM \ (NSClassFromString (@"NSCandidateListTouchBarItem")) #define NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER \ (@"NSTouchBarItemIdentifierCharacterPicker") #define NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST \ (@"NSTouchBarItemIdentifierCandidateList") #endif
  27. // EmacsMainView - (NSTouchBar *)makeTouchBar { NSTouchBar *mainBar = [[NS_TOUCH_BAR

    alloc] init]; mainBar.delegate = self; mainBar.defaultItemIdentifiers = [NSArray arrayWithObjects:NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER, NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST, nil]; return MRC_AUTORELEASE (mainBar); } - (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { NSTouchBarItem *result = nil; if ([identifier isEqualToString:NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST]) { if (candidateListTouchBarItem == nil) candidateListTouchBarItem = [[NS_CANDIDATE_LIST_TOUCH_BAR_ITEM alloc] initWithIdentifier:NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST]; result = candidateListTouchBarItem; } return result; } NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST
  28. None
  29. None
  30. None
  31. None
  32. None
  33. https://developer.apple.com/documentation/appkit/nstouchbar

  34. // EmacsMainView - (NSTouchBar *)makeTouchBar { NSTouchBar *mainBar = [[NS_TOUCH_BAR

    alloc] init]; mainBar.delegate = self; mainBar.defaultItemIdentifiers = [NSArray arrayWithObjects:NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER, NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST, nil]; return MRC_AUTORELEASE (mainBar); } - (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { NSTouchBarItem *result = nil; if ([identifier isEqualToString:NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST]) { if (candidateListTouchBarItem == nil) candidateListTouchBarItem = [[NS_CANDIDATE_LIST_TOUCH_BAR_ITEM alloc] initWithIdentifier:NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST]; result = candidateListTouchBarItem; } return result; } NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER NS_TOUCH_BAR_ITEM_IDENTIFIER_CANDIDATE_LIST
  35. ϘλϯΛදࣔͤͯ͞ΈΔ

  36. - (NSTouchBar *)makeTouchBar { NSTouchBar *mainBar = [[NS_TOUCH_BAR alloc] init];

    mainBar.delegate = self; mainBar.defaultItemIdentifiers = [NSArray arrayWithObjects:NS_TOUCH_BAR_ITEM_IDENTIFIER_CHARACTER_PICKER, NS_TOUCH_BAR_ITEM_IDENTIFIER_EMACS_FUNC, nil]; return MRC_AUTORELEASE (mainBar); } - (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { NSTouchBarItem *result = nil; if ([identifier isEqualToString:NS_TOUCH_BAR_ITEM_IDENTIFIER_EMACS_FUNC]) { NSCustomTouchBarItem *item; NSButton *button; button = [NSButton buttonWithTitle:@"foobar" target:self action:@selector(touchBarButtonAction:)]; item = [[NS_CUSTOM_TOUCH_BAR_ITEM alloc] initWithIdentifier:identifier]; item.view = button; MRC_RELEASE (scrollView); result = MRC_AUTORELEASE (item); } return result; } #define NS_TOUCH_BAR_ITEM_IDENTIFIER_EMACS_FUNC \ (@"com.blogspot.safx-dev.emacs.touchbar.")
  37. None
  38. NSApplication NSView EmacsApplication EmacsView EmacsController EmacsMainView EmacsFrameController NSApplicationDelegate NSWindowDelegate NSWindow

    emacs window EmacsWindow frame NSResponder
  39. Window Frame

  40. Window Frame

  41. NSApplication NSView EmacsApplication EmacsView EmacsController EmacsMainView EmacsFrameController NSApplicationDelegate NSWindowDelegate NSWindow

    emacs window EmacsWindow frame NSResponder
  42. ࣮ߦ →

  43. ࠷ॳͷҊ - (void)touchBarButtonAction:(NSButton *)sender { Fcall_interactively (intern ("query-replace"), Qnil, Qnil);

    }
  44. ϋϯά͢Δ

  45. Thread ϋϯά ਖ਼ৗ

  46. About Emacs-macͰ௥Ճ͞Εͨૉఢػೳ

  47. GUI -respondsToSelector: -storeEvent: kbd_buffer_store_buffered_event ΩʔϘʔυΠϕϯτͱͯ͠ѻ͏ kbd_buffer_get_event EmacsController mainThread lispThread mac-dispatch-apple-event

    about: read_char read_event_from_main_queue read_decoded_event_from_main_queue make_lispy_event command_loop access_keymap call4 mac-apple-event-mapʹΞΫηε read_key_sequence command-execute special-event-mapʹΞΫηε mac-apple-eventͳconsηϧΛ࡞੒ mac-handle-about Emacs → About Emacs lisp-function C/ObjC function EmacsController handle_action_invocation -methodSignatureForSelector: -forwardInvocation: EmacsController EmacsController keyboard.c
  48. GUI -touchBarButtonAction: -storeEvent: EmacsMainView kbd_buffer_store_buffered_event ΩʔϘʔυΠϕϯτͱͯ͠ѻ͏ kbd_buffer_get_event EmacsController mainThread lispThread

    mac-dispatch-apple-event Touch read_char read_event_from_main_queue read_decoded_event_from_main_queue make_lispy_event command_loop access_keymap call4 mac-apple-event-mapʹΞΫηε read_key_sequence command-execute special-event-mapʹΞΫηε mac-apple-eventͳconsηϧΛ࡞੒ mac-handle-foobar Touch bar lisp-function C/ObjC function keyboard.c
  49. վྑҊ - (void)touchBarButtonAction:(id)sender { struct frame *f = [self emacsFrame];

    struct input_event inev; EVENT_INIT (inev); inev.kind = MAC_APPLE_EVENT; inev.x = Qaction; inev.y = intern ("foobar"); XSETFRAME (inev.frame_or_window, f); inev.arg = Fcons (build_string ("aevt"), Qnil); [emacsController storeEvent:&inev]; } (define-key mac-apple-event-map [action foobar] 'mac-handle-foobar) (defun mac-handle-foobar () (interactive) (print "foobar")) ޙ͸Emacs-mac͕΍ͬͯ͘ΕΔ
  50. վྑҊ

  51. Elisp͔ΒจࣈྻΛऔΔ ←

  52. άϩʔόϧม਺Λ௥Ճ͢Δ Lisp_Object f_Vmac_touch_bar_buttons; #define Vmac_touch_bar_buttons globals.f_Vmac_touch_bar_buttons global.h (ࣗಈੜ੒͞ΕΔ) DEFVAR_LISP ("mac-touch-bar-buttons",

    Vmac_touch_bar_buttons, doc: /* Vector for Touch bar buttons of Macbook Pro. */); Vmac_touch_bar_buttons = Qnil; macselect.c
  53. άϩʔόϧม਺Λ௥Ճ͢Δ • Q Ͱ͸͡·Δ΋ͷ͸ఆ਺ • V Ͱ͸͡·Δ΋ͷ͸ม਺ • doc: Λॻ͍͓ͯ͘ͱdescribe-variableͰࢀর͞ΕΔ

  54. ద౰ͳλΠϛϯάͰߋ৽ • mac_read_socket͋ͨΓ͕ϙʔϦϯά͍ͯ͠Δ if (old_mac_touch_bar_buttons != Vmac_touch_bar_buttons) { old_mac_touch_bar_buttons =

    Vmac_touch_bar_buttons; NSApp.touchBar = nil; }
  55. TouchBarͷߋ৽ - (NSTouchBar *)makeTouchBar { NSTouchBar *mainBar = [[NS_TOUCH_BAR alloc]

    init]; NSMutableArray *items = [NSMutableArray array]; if (!NILP(Vmac_touch_bar_buttons)) { Lisp_Object rest; for (rest = Vmac_touch_bar_buttons; CONSP (rest); rest = XCDR (rest)) { if (STRINGP (XCAR (rest))) { NSString *label = [NSString stringWithUTF8LispString:(XCAR (rest))]; NSString *ident = [NSString stringWithFormat:@"%@%@", NS_TOUCH_BAR_ITEM_IDENTIFIER_PREFIX, label]; [items addObject:ident]; } } } mainBar.delegate = self; mainBar.defaultItemIdentifiers = [items copy]; return MRC_AUTORELEASE (mainBar); }
  56. - (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { NSTouchBarItem *result = nil;

    if ([identifier hasPrefix:NS_TOUCH_BAR_ITEM_IDENTIFIER_PREFIX] && !NILP(Vmac_touch_bar_buttons)) { Lisp_Object rest; for (rest = Vmac_touch_bar_buttons; CONSP (rest); rest = XCDR (rest)) { if (STRINGP (XCAR (rest))) { NSString *label = [NSString stringWithUTF8LispString:(XCAR (rest))]; NSString *ident = [NSString stringWithFormat:@"%@%@", NS_TOUCH_BAR_ITEM_IDENTIFIER_PREFIX, label]; if ([identifier isEqualToString:ident]) { NSCustomTouchBarItem *item; NSButton *button; button = [NSButton buttonWithTitle:label target:self action:@selector(touchBarButtonAction:)]; item = [[NS_CUSTOM_TOUCH_BAR_ITEM alloc] initWithIdentifier:identifier]; item.view = button; result = MRC_AUTORELEASE (item); break; } } } } return result; }