1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

reddit-emacs-tips-n-tricks(25/03/02更新)を日本語訳してみた

Last updated at Posted at 2025-05-01

Redditにr/emacsというsubredditがあります。日本の2ch(今は5ch)にもEmacsのスレッドがあり、今より活発に投稿があって楽しんだものですが、subredditの方は会員数7万7千だけあって日々何かしらのポストがあり楽しんでいます。現在の日本のEmacsコミュニティ、emacs-jpにも#today-i-learnedというチャンネルがありそこそこ流量があり楽しめるのですが、やはりメンバ数ではあちらが上なので、追加の読み物としてsubredditは重宝しています。

このsubredditでTILに相当するのがWeekly Tips, Tricks, &c. Thread、現在はモデレーターの変更もあって"Fortnightly Tips, Tricks, and Questions"という名前のスレッドです。

このスレッド専用の検索ページもあるんですが、Github/Git Actionsで毎週このスレッドを自動で収集、公開してくださっているのがLaurenceWarneさんのレポジトリです。

前置きが長くなりましたが、この投稿はこのレポジトリの2025/03/02のコミットです。


u/SlowMovingTarget

🔗

Votes 38

目新しくもない(古参なら周知の)コツではあるが、テキストを別の複数のテキストに分割するすぐれ技:

  1. テキストを選択(Evilならvisualモード、他はその類いの機能を使って)
  2. M-x write-regionしてから選択そたテキストを書き出すファイルの名前を入力する。手っ取り早くて便利だ

これはマニュアルに記載の小技だがマジ便利

他にコツがあるとすればマニュアルを読むことじゃないかな :)

u/TheDrownedKraken

🔗

Votes 37

このサブレディット、更新間隔もう少し長い方がイクナイ? 普通にイカしたTipsがあっても儚いRedditでは容易にロストしてしまうだろう。

このサブレディットのサイズなら月刊くらいが丁度よいのでは。

u/PriorOutcome

🔗

Votes 33

リージョンをアクティブにしてundoすると、ファイル全体ではなくリージョンの変更だけをundoできるよ。

u/zupatol

🔗

Votes 29

何年かEmacsを使って2つ目に記述したelisp関数が、Emacsで閲覧中のコードをGithubでオープンする関数。

(defun open-on-github ()
  (interactive)
  (let
      ((repo-url (magit-git-string "remote" "get-url" "--push" "origin"))
       (commit-hash (magit-git-string "rev-parse" "HEAD"))
       (start-line (if (use-region-p)
                       (line-number-at-pos (region-beginning))
                     (line-number-at-pos)))
       (end-line (if (use-region-p) (line-number-at-pos (region-end)))))
    (unless repo-url (error  "not in a git repo"))
    (browse-url
     (concat
      (substring repo-url 0 -4)
      "/blob/"
      commit-hash
      "/"
      (substring buffer-file-name (length (projectile-project-root)))
      "#L" (number-to-string start-line)
      (if (and (use-region-p) (< 0 (- end-line start-line)))
          (concat "..L" (number-to-string end-line)))
      ))))

u/[あぼーん]

🔗

Votes 24

あぼーん

u/sandinmyjoints

🔗

Votes 24

最近時間をかけて調べるまでは、electric-pairsが間違っていると何年も思っていた。定期的に遭遇するわたしの嫌いだった挙動の1つが(パイプ記号は引用符を1回タイプしたときのポイント位置):

""|word

引用符を2つ欲しい訳ではない場合だ。

この挙動のほとんどはelectric-pair-inhibit-predicateによって制御されている。わたしはelectric-pair-preserve-balancetにセットして、デフォルト(electric-pair-default-inhibit)を使用していた。全体的にはわたしにとってelectric-pair-preserve-balanceが役に立たないことに気づいた。わたしが欲しいのはelectric-pair-preserve-balancenilの際にelectric-pair-default-inhibitが使用するelectric-pair-conservative-inhibitに近いものだと気づいたのだ。electric-pair-preserve-balanceをオフにすることで上記ケースは解決した。

それでも同じくらいの頻度で発生する下記ケースにたいしてはelectric-pair-conservative-inhibitで処理できなかった:

word|""

なのでビルトインのelectric-pair-conservative-inhibitorに条件を1つ追加した独自の関数を記述して、やっと自然で正しいと感じられる方法で動作させることができた!

(defun my/electric-pair-conservative-inhibit (char)
  (or
   ;; 次も同じ文字ならペアリングしない
   (eq char (char-after))
   ;; ""や((の2つ目の文字でペアリングさせない
   ;; 2番目の ""または((。
   (and (eq char (char-before))

(eq char (char-before (1- (point)))))

;; 単語の隣ではペアリングさせたくないことにも気がついた
(eq (char-syntax (following-char)) ?w)
;; 単語終端ではカッコ以外はペアリングさせない
(and
 (eq (char-syntax (char-before (1- (point)))) ?w)
 (eq (preceding-char) char)
 (not (eq (char-syntax (preceding-char)) 40) ;; 40は開カッコだ
      ))))

u/Gangsir

🔗

Votes 22

back-to-indentation、これを知るまではいつもC-a M-f M-bのようなアクロバティックなトリプルコンボをこなしていた。

これはM-mにバインドされている関数だ。その行の空白文字ではない最初の文字にジャンプできる。逆に作用する点にも妙味がある。行の先頭より前にいる場合には前方、どこか中間にいる場合には後方にジャンプするのだ。

インデントされていない行であってもC-aと同じように機能する。

マクロの途中で行の先頭の文字にポイントをリセットするのに特に重宝する。

u/geza42

🔗

Votes 21

Yasnippetには取り囲む機能がある。たとえば以下のようなC++のnamespaceのスニペットなら:

# -*- mode: snippet -*-
# name: namespace-surround
# key: ns
# --
namespace ${1}${1:$(if (> (length yas-text) 0) " {" "{")}
`yas-selected-text`$0
} // namespace${1:$(if (> (length yas-text) 0) (concat " "
(substring-no-properties yas-text)) "")}

そして(yas-expand-snippet (yas-lookup-snippet "namespace-surround"))を何かのキーにバインドしてそれを押下すれば、選択されているコードを"namespace NAME {"
and "} // namespace NAME"で括れるのだ。

img

u/howardthegeek

🔗

Votes 21

eshellでは$$が最後のコマンドの出力に置き換えられることを学んだ。

u/PriorOutcome

🔗

Votes 20

リージョンがアクティブだとrectangle-mark-modeと通常のモードを自由に切り替えられる。切り替える前にアクティブなリージョンの選択を解除する必要はない。

u/PriorOutcome

🔗

Votes 20

何週間か前のアップデートから、何度かの紆余曲折を経た後、このスレッドの過去コメントを解析して、週単位でhttps://github.com/LaurenceWarne/reddit-emacs-tips-n-tricks/blob/master/out.mdに自動更新するようにした。

一部のコードスニペットの壊れたハイライトの修正も行った。過去のスレッドすべてが解析されていれば幸いだ。200以上のコメント(vode順)があるので、特に探しているトピックがあればmagitCTRL-f(ブラウザの頁内検索)といった使い方ができるだろう。

u/TeMPOraLPL

🔗

Votes 20

Emacs
28.1の新機能の1つにshortdocがある。これは何か面白いElisp関数を見つけたときの自分用の"cheatsheet(早見表))"の保守に最適だ。たとえばEmacsセッションで以下をevalすると:

(define-short-documentation-group my-datetime
  "時刻問い合わせ"
  (current-time
   :eval (current-time))
  (float-time
   :eval (float-time))
  
  "時刻書式"
  (time-convert
   :eval (time-convert (current-time))
   :eval (time-convert (current-time) 'list)
   :eval (time-convert (current-time) 100000)
   :eval (time-convert (current-time) 200000)
   :eval (time-convert (current-time) t)
   :eval (time-convert (current-time) 'integer))
  
  (float-time
   :eval (float-time (current-time))))

そうすればM-x shortdoc-display-groupのオプションとしてmy-datetimeグループが表示されるようになる。それだけではなく上記に含まれるいずれかの関数のヘルプを閲覧すると、Helpバッファーからshortdocグループのmy-datetimeを逆参照できるのだ!

この例はビルトインの時間関係の関数を調べているときに記述した最初の自分用cheatsheetだ。使用する手順の詳細については、define-short-documentation-groupマクロを参照して欲しい。使用例としてはdefine-short-documentation-groupのソースにジャンプして少し下にスクロールすれば、デフォルトのshortdocグループが定義されている。

u/SamTheComputerSlayer

🔗

Votes 20

この問題解決には少々のHackが必要かもしれない…

flyspellで単語修正にmouse-2を使う必要があるのは煩わしいが、かといってキーボードで行えるようにメジャーモードのキーバインディングを犠牲にしたくない。しかし実際にはflyspellは綴り間違いの単語にoverlayを作成してkeymapを割り当てているので、わたしが非常に素晴らしいと思うことをあなたも行える筈だ。つまりflyspell-mouse-mapflyspell-correct-at-pointを""にバインドすれば、綴り間違いの単語上にカーソルがあるときにリターンを押下するだけで単語を訂正できるのだ!

しかしoverlayにkeymapを割り当て可能という事実はとても役に立つように思うので、将来は間違いなく使用されるテクニックだろう。

u/ImJustPassinBy

🔗

Votes 20

use-packageにはパッケージそれぞれが起動時に要したロード時間の概要を報告するためのビルトイン機能(esupがあり、実行すれば大体においてよい結果を得られるだろう。ただしEmacs
snapでは既知の問題もある:

  1. init.elの先頭に(setq use-package-compute-statistics t)を記述
  2. Emacsを再起動
  3. M-x use-package-reportを実行する

一番時間を喰うパッケージは何か、そのコストに見合う価値があるのか?
わたしの場合はpdf-tools,だったが、Emacsでpdfを扱える満足できる選択肢は他に存在しない。

u/Argletrough

🔗

Votes 20

ビルトインのmode-localパッケージを使えば、メジャーモードに応じて変数の値をセットできる。
The built-in package lets you set the values of variables based on the
major mode.
これを使えば、多くの人たちのコンフィグでよく目にする、お約束の(add-hook 'foo-mode-hook (lambda () (setq ...))を使わずに済むだろう。たとえば:

(setq-mode-local prog-mode fill-column 100)
(setq-mode-local org-mode display-line-numbers 'visual)

mode-localで関連devdocを事前選択する例も参照して欲しい。

u/AndreaSomePostfix

🔗

Votes 19

org-modeは素晴らしい!

先日、他の人にノートのアウトラインだけ送りたいときにorg-copy-visibleを見つけた。

この関数(デフォルトではC-c C-x vにバインドされている)は選択したリージョンのアウトラインだけをコピーするのだ。非常に便利!

u/vkazanov

🔗

Votes 18

18年使い倒したEmacs関連の原則を吐き出そう:

  1. IDEの静的セットアップの複製に挑戦しないこと。流動するのがEmacsだ
  2. この流動性を可能に保つためにEmacserにはEmacs Lispが不可避である
  3. 言語を問わずは言語次第に勝る
  4. display-alist、素早いウィンドウ操作、winner-modeを受け入れろ
  5. 数年に一度は".emacs.el"をリセットして、新発明を取り込め
  6. すべてのドキュメント、プロジェクト、メモにorg-mode/org-roamを使え。アジェンダは固定ではない。クエリー、フィルター、微調整、思考展開を使え
  7. コンテキスト感応のDWIM(Do what Imean)は、常に大量のキーバインディングに勝る。
  8. どこでも何にでも補完を使え(verticoは神)
  9. Emacsコア開発、お気に入りのパッケージに貢献すべし

わたしが初心者であっても、物事は変えることができるのだ。

u/alvarogonzalezs

🔗

Votes 18

わたしはffapのヘビーユーザーだ。カーソルの下に名前があるファイルをオープンするときは、いつもM-xでこの関数を使っている。

しかし今週ffap-bindingsを見つけた。これはffapの使用が有意義なときに一部のキーバインディングを置き換える関数だ。たとえばfind-filefind-file-at-pointに置き換えられるので、コストゼロで通常のキーバインディングを充実させられる。

u/github-alphapapa

🔗

Votes 18

わたしが再発見した有名なEmacsコンフィグだ。イカしたコンフィグを見つけられるだろう。

u/sauntcartas

🔗

Votes 17

最近発見したthing-at-point-looking-atだが、新たな種類の"thing"を完全に定義するよりも、この関数自体の方が使いやすいように思える。

ポイント位置にあるJiraチケット識別子を手軽に認識できればそれを簡単にブラウズできるな、と思っていた。基本的にチケットIDはアルファベット、ハイフン、数字並びからなるシーケンスだ。最初にsymbol-at-pointを試したがURLの一部であるようなチケットIDだと、/のように隣接する無関係な文字まで含まれてしまうかもしれない。thingatptのソースを熟読して、最終的に辿り着いたのがthing-at-point-looking-atである:

(defun browse-ticket-at-point ()
  (interactive)
  (if (thing-at-point-looking-at (rx (+ alpha) "-" (+ digit)))
      (browse-url (format "https://jirahost/browse/%s" (match-string 0)))
    (error "No ticket at point")))

お茶の子さいさいよ!

u/tryptych

🔗

Votes 17

use-packageを用いたスタートアップ時間の最適化というご機嫌な時間稼ぎに時間を費やした後に、それに関するブログ記事を記述した。別の投稿に分ける意味があった訳ではない。use-packageによるスタートアップ時間の最適化に関する提案はいくつか存在するが、それらのうちでautoloadeval-after-load等に如何にして結び付いたのかを実際に説明していないように思えたので、macroexpandを探求して知識を得るように勧める記事を投稿した訳だ。

u/AffectionateAd8985

🔗

Votes 17

(add-hook 'org-mode-hook (lambda () (org-next-visible-heading 1)))

orgファイルをオープンしたらorg-use-speed-commandsで最初のヘディングに移動、npのキーだけで手早くorgファイルを閲覧できる。

u/oantolin

🔗

Votes 17

orgモードのリンク技を2つ:

  1. "RET"押下でリンクを辿るために(setq org-return-follows-link t)。"RET"の伝統的動作、すなわち改行の挿入はC-q C-jで簡単に実行できる。

  2. リンク先を確認したいことがよくあるが、以下のメソッドのいずれかを使っていた:

    • マウスをリンク上に移動
    • org-insert-linkの実行とキャンセル(C-c C-lでリンク先確認したら

C-g<

  • org-toggle-link-displayはちゃんとフォーマットされたリンクと生のソースを切り替えるが、

とても見にくい


しかしより優れていたのはdisplay-local-help (C-h .)を使うというオプションだ。これはエコーエリアにツールチップを表示する関数だ。(setq help-at-pt-display-when-idle t)とすればポイント位置のツールチップを自動的にエコーエリアに表示することさえできる。遅延制御用に変数help-at-pt-timer-delayがあるが、わたしの好みで0にセットしている。(setq help-at-pt-timer-delay 0)だけ使っても効果がないことに注意。customize-set-variableを使用するか、タイマーをキャンセルして新たなタイマーをセット(以下参照)する必要がある。

これらのhelp-at-pt変数はorgのリンクだけに留まらずツールチップすべての動作を制御すること、そしてorgモードのバッファーでの動作を本当に変更したい訳ではないことにすぐに気がついた。以下のようにすればよいのだ:

(defun echo-area-tooltips ()
  "カレントバッファーのエコーエリアにツールチップを自動表示する"
  (setq-local help-at-pt-display-when-idle t
              help-at-pt-timer-delay 0)
  (help-at-pt-cancel-timer)
  (help-at-pt-set-timer))

(add-hook 'org-mode-hook #'echo-area-tooltips)

u/WorldsEndless

🔗

Votes 16

文芸的プログラミングの最中にコードブロックを分割したいときがよくある。複数の関数に含まれているコードブロックを個別のブロックにコピペ、それらの間にテキストを記述したいとかだ。BEGIN_SRCブロック内にカーソルがあるときにはコマンドorg-babel-demarcate-block
(C-c C-v d)がピッタリだ。

u/slinchisl

🔗

Votes 16

遂に自分のEmacsコンフィグ用の小さなREADMEの記述に取り掛かった。本当にお気に入りの自家製部分が強調されたものを。そんなときに標準的な方法だとは思うが、これが役に立つことに気づいていない人もここにはいるかもしれない:

https://gitlab.com/slotThe/dotfiles/-/tree/master/emacs/.config/emacs

u/meain

🔗

Votes 16

コンパイルが失敗したときにコンパイルバッファーの背景色を明るい赤に変更するために以下のスニペットを使用している。テストを実行するために2つ目のモニターでコンパイルバッファーを使用しているが、これはとても役に立っている。

(defun meain/compilation-colorcode (_buffer string)
    "コンパイル失敗時に_BUFFERの背景色を赤に変更する"
    (unless (string-prefix-p "finished" string) ; 成功時の色変更はかえって気が散る
    (face-remap-add-relative 'default 'diff-hl-delete)))
(add-to-list 'compilation-finish-functions 'meain/compilation-colorcode)

u/TeMPOraLPL

🔗

Votes 16

あなたの一日の終わりがわたしのように真夜中過ぎならOrgモードのアジェンダに挙げられている最後のタスクのいくつかの処遇に手こずっているかもしれない。幸いOrgモードにはわたしが"25時間モード"と呼んでいるものがある。

;; その日の終わりを午前3時とみなす
(setq org-extend-today-until 3)
    
;; timestamp処理関数にこれを考慮させる
(setq org-use-effective-time t)

アジェンダビュー、スケジュールコマンド、リピーター等と組み合わせて使うことで一日の終わりを真夜中過ぎに延長できる。org-extend-today-untilの制限に達するまでは現在時刻を23:59とみなせるのだ。これを有効にしておけば、リピーターかつ01:00に完了すべきタスクを一日戻って手作業でリスケする必要はなくなるだろう。

u/rucci99

🔗

Votes 16

Magitがコミットしていないファイルの変更は自動的にバックアップできることに気がついた。オンラインマニュアルのリンク: Magit Wip
Modes

u/[あぼーん]

🔗

Votes 16

わたしはtransientを使っており愛してもいる。大量のコマンドがあるが、以下はウィンドウ操作だけを抜粋したものだ。個人的にはs-wにバインドしている。フレーム内のウィンドウの再配置にはbuffer-moveを使っている。

;; 訳注: 動くように若干手直し
(require 'buffer-move)
(require 'winner)
(transient-define-prefix transient-window ()
  "もっともよく使うウィンドウ用のコマンド"
  [["Splits"
    ("s" "Horizontal" split-window-below)
    ("v" "Vertical"   split-window-right)
    ("b" "Balance"    balance-windows)
    ("f" "Fit"        fit-window-to-buffer)]
   ["Window"
    ("c" "Clone Indirectl" clone-indirect-buffer)
    ("t" "Tear Off" tear-off-window)
    ("k" "Kill" delete-window)
    ("K" "Kill Buffer+Win"  kill-buffer-and-window)
    ("o" "Kill Others"  delete-other-windows)
    ("m" "Maximize" maximize-window)]
   ["Navigate"
    ("<left>"  "←" windmove-left  :transient t)
    ("<right>" "→" windmove-right :transient t)
    ("<up>"    "↑" windmove-up    :transient t)
    ("<down>"  "↓" windmove-down  :transient t)]
   ["Move"
    ("S-<left>"  "S-←" buf-move-left  :transient t)
    ("S-<right>" "S-→" buf-move-right :transient t)
    ("S-<up>"    "S-↑" buf-move-up    :transient t)
    ("S-<down>"  "S-↓" buf-move-down  :transient t)]
   ["Undo/Redo"
    ("s-z" "Winner Undo" winner-undo :transient t)
    ("s-Z" "Winner Redo" winner-redo :transient t)]])

u/gopar

🔗

Votes 16

わたしが行ったのは非常にシンプルだ。ほとんどすべてのモードで";" (セミコロン)を"\_"
(アンダーバー)にリマップしただけ。主にPythonで作業しているので、毎回"SHIFT-DASH"というキーストロークを押すより余程簡単だからだ(訳注:
US配列キーボードではアンダーバーをシフトキーを押しながらダッシュを押下して入力する)。普通にセミコロンを入力したければ"C-u
;"でセミコロンを入力できる。

C/C++等のモードでもこれをセットしている。自動的に最後の文字をセットすることで(アンダーバーなら)セミコロンを入力するのだ。

"|"はカーソル

int a = 10\\\*10\\\_|

//これは以下に変換される

int a = 10\\\*10;

| (カーソルは新たな行に移動)

とてもシンプルな時間節約だ\o/

u/TheDrownedKraken

🔗

Votes 16

このスレの質問とヒントはアーカイブしておいた方がよいだろう。ここではいつもクールな技を見つけられるが、後から探すのはとっても難しいように思える。

u/WorldsEndless

🔗

Votes 15

(delete-blank-lines) (C-x C-o)は大いに役に立つ。テキストのクリーンアップに毎日使っている。一度押下すれば空行を1行残して他のすべての空行和削除するのだ。2回押下すれば残りの1行も削除する。

u/PriorOutcome

🔗

Votes 15

古くからあるquery-replaceには、素のままでも多くのイカした機能がある。まずアクティブなリージョンを考慮する点だ(リージョンがアクティブならリージョン内でのみ問い合わせと置換を行う)。通常の、y/nに加えて役に立つキーがたくさんあるのだ:

!: 残りのマッチすべてを置換

u: 最後の置換をundo

E: 置換する文字列を臨機応変に変更

?を使えば他にもたくさんあることが判るだろう。

u/agumonkey

🔗

Votes 15

Emacsとは本来関係ないかもしれないが、Jack
Rusher氏がコーディング、歴史(Lispマシン、smalltalkなど)、最近ではclosureベースのツールに関する興味深いアイデアとともにプログラミングの"ux
/ ergonomics / pragmatics"について語っている

https://www.youtube.com/watch?v=8Ab3ArE8W3s

楽しんで貰えれば幸いだ。

💩

u/pathemata

🔗

Votes 15

最近使って素晴らしかったのはconsult-ripgrepコマンドとしてripgrep-allを使うとPDFの中も検索すること。

orderlessディスパッチャによる検索フィルタリングの制御は驚異的だ。文字列除外は!、正確にマッチさせる場合には=を使っている。

機能を分解できるembark-collectも素晴らしい。collectバッファーでconsult-lineを使って更にフィルタリングできるし、PDFをオープンすることさえできるのだ。

u/globalcandyamnesia

🔗

Votes 15

自分の声の女性化に挑戦しているんだがOrgモードは重宝している。

(org-babel-do-load-languages 'org-babel-load-lanuages
  '((shell . t)))
    
(setq org-capture-templates
  ~(("v" "Voice" entry
    (file+olp+datetree ,(concat my-org-directory "voice/training.org"))
    ,(concat
      "* Record \n"
      "\n"
      "  #+begin_src sh\n"
      "    rec %(format-time-string \"%Y-%m-%d-%H.%M.%S\").aiff\n"
      "  #+end\_src\n"
      "\n"
      "* Play\n"
      "  #+begin_src sh\n"
      "    play %(format-time-string \"%Y-%m-%d-%H.%M.%S\").aiff\n"
      "  #+end_src\n")
    :immediate-finish t
    :jump-to-captured t)))

Linux用の"SoX"が必要だ。Recordソースブロックに移動してC-c C-cで録音スタート、C-gでストップする。録音の再生はPlayソースブロックに移動してC-c C-cだ。トランスジェンダーコミュニティだけではなく、基本的な音声記録にとっても役に立つのではないかと思う。

u/oantolin

🔗

Votes 15

プレビュー付きでマッチの検索と置換を行いたければ、query-replace-regexpを直接使わないこと。まずisearch-forward-regexpによるregexpの検索で開始する。これはマッチを対話的にハイライトするので、正しいregexpが得られたらisearch-query-replaceを実行するのだ(isearch-mode-mapではM-%にバインドされている)。

isearch-query-replace-regexpも存在することに注意。とはいえ使う必要はないと思うが。isearch-query-replaceはそのisearchセッションがregexpを対象としているかを自動的に検知してくれる。isearch-query-replaceのdoc文字列には、このナイスな機能が記述されていないように見える。

u/[あぼーん]

🔗

Votes 15

今週ネイティブコンパイル版のemacsブランチに移行した。ぎこちない部分もあるが、"pdf-tools"を含むすべてがそのまま動作するようだ。凄い性能改善だね。

u/ImJustPassinBy

🔗

Votes 15

役に立つパッケージ全般にいて十分言及されていないと思うのがhelpfulだ。これはヘルプバッファーを強化するためのパッケージだ(改善されたハイライト、追加の情報など;
Githubのスクリーンショットで確認できる)。ヘルプ用のキーバインディングをリバインドするだけだ。呼び出されるまでロードは遅延されるので、起動時間への影響も心配無用である。

(use-package helpful
  :bind
  (("C-h f" . helpful-function)
   ("C-h x" . helpful-command)
   ("C-h k" . helpful-key)
   ("C-h v" . helpful-variable)))

u/alvarogonzalezs

🔗

Votes 14

プロジェクトのファイルから文字列の出現箇所すべてを検索する。ただし特定の種類のファイルだけから検索する必要がある場合には、consult-ripgrepの検索パターンに-- -tを使うことができる。

htmlタイプのファイルでfancystrを検索する場合の検索パターンはfancystr -- -t htmlといった具合だ。

consult-grepのドキュメントには--の後に指定したオプションはコマンドライン引数としてgrepに渡されると記述されている。プロンプト入力全体の形式は以下のようになるだろう:

#async-input -- rg-opts#filter-string

これを発見して以来、毎日のように使用している。

u/leothrix

🔗

Votes 14

use-packageのユーザーの人たち(大部分の人がユーザーだと思うが)は、簡単にプロファイリングが行えることをご存知だろうか?
esupではない。あなたのinit.elの起動時間を有意に短縮ために最適化すべき箇所を非常に直截的に探し出すビルトイン能力のことだ。

use-packageのロード直後にuse-package-compute-statisticsを有効にしてみよう:

(setq use-package-compute-statistics t)

Emacsを再起動してuse-package-reportを呼び出して欲しい。use-packageが管理しているパッケージそれぞれについてロード時間が記された表が得られる筈だ。これを発見したことで、正しく遅延されていなかったいくつかのパッケージに:hookキーワードを追加して、起動時間を即座に半分にする方法を見つけ出すことができたのだ。

u/com4

🔗

Votes 14

Emacsコアへのeglot導入に備えて、lsp-modeから切り替えることにした。結果としてflycheckからflymakeへの切り替えも行った。flycheckが優れている点の1つが、チェッカーの積み重ねだ。Pythonのコーディングをする際にはスタイルとして"flake8"、タイプには"mypy"(とすでにあるLSP)を使うのがわたしの好みだ。

Flymakeはチェッカーの多重化ができるがLSPチェッカーを"追加"する際に、eglotがこれらのチェッカーを阻害するのだ。Eglotを含んだFlymakeの多重化チェッカーを得るには、Eglotの実行後に他のチェッカーを追加することができる。

たとえば以下はPyrightのタイプチェックとflake8のスタイルチェックを含んだ、Python用のシンプルなセットアップだ

;; デフォルトではPythonのスタイルチェッカーにflake8を使用する
(setq python-flymake-command '("flake8" "-"))
    
(use-package eglot
  :hook ((python-mode . eglot-ensure)
         (eglot-managed-mode
	  . (lambda ()
	      ;; eglot起動時にチェッカーを阻害するのでFlymakeを再度有効化する
	      (when (derived-mode-p 'python-mode)
		(add-hook 'flymake-diagnostic-functions 
                          'python-flymake nil t)))))
    
  :custom
  ;; 管理された最後のバッファーをkillした後にサーバーをシャットダウン
  (eglot-autoshutdown t)
  :bind
  (("C-c l r" . eglot-rename))
  :config
  (add-to-list 'eglot-server-programs
               `(python-mode "pyright-langserver" "-w" "--stdio")))

残りはすべて"mypy"に残しておく。Flymakeは元々既存の"mypy"が使用するチェッカーの作成に"Proc"メソッドを使用している。といった訳でわたしが新しいスタイルで記述したmypyチェッカーのヒントとコツをおまけにつけておこう。これは以下のようにeglotの使用時に有効にできる:

(use-package flymake-mypy
  :straight (flymake-mypy
             :type git
             :host github
             :repo "com4/flymake-mypy")
  :hook ((eglot-managed-mode . (lambda ()
				 (when (derived-mode-p 'python-mode)
				   (flymake-mypy-enable))))))

Pythonバッファーのオープン後にM-x flymake-running-backendsを実行すると多重化されたチェッカーのリスト、Running backends: eglot-flymake-backend, flymake-mypy--run, python-flymakeが出迎えてくれる筈だ。

u/thr33body

🔗

Votes 14

特段目新しくもない話しかもしれないが共有したいと思う。SpacemacsやDoomを使うことにうんざりしているようなら、自分でインストールしてセットアップした方が遥かに簡単だったという経験についてだ。実際に動作するまであれこれ行ったのは数日だが、今では問題の診断もずいぶんシンプルになった。SpacemacsとDoomのどちらも不要という訳ではない。Emacsについてもっと学習したかったこと、そして本当に満足のいく結果が得られたらという経験だけは伝えておきたい。

u/eltuxo

🔗

Votes 14

EshellでTrampを使って作業するのが簡単過ぎて、逆に間違ったマシンで簡単にコマンドを走らせることができてしまうことが悩みの種だ。

なので現在Trampのセッション中であることが気付けるように、プロンプトの色を変更する小さな関数を実装した。

(require 'subr-x)  
(defun tuxo/prompt-color-tramp ()  
"Trampセッションオープン中ならプロンプトの色を変更"  
  (if (file-remote-p default-directory)  
      (set-face-foreground 'eshell-prompt "red")  
      (set-face-foreground 'eshell-prompt "green")))
    
(use-package eshell
  :hook (eshell-post-command . tuxo/prompt-color-tramp))

この問題を改善し得る方法が他にあれば、是非教えてもらえないだろうか?

u/Stefan-Kangas

🔗

Votes 14

とても洒落た小技だと思う: ポイント位置を保持したまま1行単位で上下にスクロールする小技だ:

(setq scroll-preserve-screen-position 1)
(global-set-key (kbd "M-n") (kbd "C-u 1 C-v"))
(global-set-key (kbd "M-p") (kbd "C-u 1 M-v"))

出典:http://pragmaticemacs.com/emacs/scrolling-and-moving-by-line

u/Tatrics

🔗

Votes 14

ゆっくりとではあるが、代替えとなるシェルを記述しているhttps://github.com/TatriX/tshell

REPL風のインターフェイスではなく単一のバッファー(ファイルでもよい)にすべてのコマンドを入力して、別のバッファーに出力させるような使い方をする。たとえば"scratch"バッファーにelisp
コードを記述したら、C-x C-eで評価するのだ。

まだ初期の開発ステージではあるが、以前は昔ながらのシェルで行っていたタスクのほとんどはこなせている。

何か感銘を受けたことや、改善し得ると感じたことがあれば是非教えて欲しい!

u/[あぼーん]

🔗

Votes 14

selectedという素晴らしいパッケージを見つけた。リージョンがアクティブなときは常にアクティブになるキーマップを作成するためのパッケージだ。わたしはnext-lineprevious-linerectangle-mark-modeend-of-lineupcase-dwimexchange-point-and-mark等をバインドしている。このパッケージのおかげでアクティブなリージョンにたいする編集や処理が極めて容易に行えるようになった。god-modeやVimのvisualモードといった類の1つである。

u/ImJustPassinBy

🔗

Votes 13

定期的にEmacsの下端に視線を移動するのが最近億劫になってきたので、その情報を中央にポップアップするposframesに切り替えた。わたしが使ったパッケージは:

vertico用にvertico-posframewhich-key用はwhich-key-posframe、そしてすべてのtransientコマンド(magitcasual-suite)にtransient-posframeをインストールした。

あなたがどんなパッケージを使っているかに依らず、すでに適切な*-posframeがあるかもしれない。それらのパッケージは簡単にインストールできる筈だ:

(use-package vertico-posframe
  :init
  (vertico-posframe-mode))
(use-package which-key-posframe
  :init
  (which-key-posframe-mode))
(use-package transient-posframe
  :init
  (transient-posframe-mode))

u/mlk

🔗

Votes 13

outline-minor-modeでアジェンダを折り畳み式にした。動作させるためには"* Current Tasks", "* Today
Agenda*"といった具合にアジェンダのヘディング(org-agenda-overriding-header)をアスタリスクで始まる名前にする必要がある。

  (defun my/org-agenda-fold()
  "\"* \" tabで始まるアジェンダをfold(折り畳み)"
    (interactive)
    (setq-local outline-regexp "^\\* ")
    (setq-local outline-heading-end-regexp "\n")
    (setq-local outline-minor-mode-prefix (kbd "C-'"))
    (outline-minor-mode)
    (local-set-key outline-minor-mode-prefix outline-mode-prefix-map)
    (org-defkey org-agenda-mode-map [(tab)] #'outline-toggle-children)
    (map!
      :after evil-org-agenda
      :map evil-org-agenda-mode-map
      :m "<tab>" #'outline-toggle-children
      :m "<return>" #'org-agenda-goto
      :m "S-<return>" #'org-agenda-switch-to
      :m "C-<return>" #'org-agenda-recenter))
    
(add-hook 'org-agenda-mode-hook 'my/org-agenda-fold)

u/geza42

🔗

Votes 13

verticoの高さを15から"ほとんどフレーム全体"の間に切り替えられる。verticoの高さは呼び出し時には常に15にする。しかしマッチが大量にある際には以下のバインディングを押下すれば、フレーム全体にverticoがマッチを表示するので一瞥しやすくなるだろう。たとえばconsult-bufferが大量のバッファーを表示する場合も役に立つと思う。

(advice-add 'vertico--setup :before (lambda () (setq vertico-count 15)))
(define-key minibuffer-local-map (kbd "s-'") (lambda ()
  (interactive)
  (let ((vertico-resize t))
    (setq vertico-count (if (= vertico-count 15) (- (frame-height) 5) 15))
    (vertico--exhibit))))

他に役に立つ機能に、consult-bufferで手作業でembark-actを呼び出さずにバッファーをkillするというのがある。わたしがHelmで見過ごしていたのが、この1つのバインディングだけでアクションが実行できる機能だ(embark-act呼び出しの中間的なバインディングが不要)。embarkからロジックの一部をそのまま拝借しているので、不要なコードが含まれているかもしれない。

(defun my-embark-M-k (&optional arg)
  (interactive "P")
  (require 'embark)
  (if-let ((targets (embark--targets)))
      (let* ((target
              (or (nth
                  (if (or (null arg) (minibufferp))
                      0
                    (mod (prefix-numeric-value arg) (length targets)))
                  targets)))
            (type (plist-get target :type)))
        (cond
         ((eq type 'buffer)
          (let ((embark-pre-action-hooks))
            (embark--act 'kill-buffer target)))))))

(define-key minibuffer-local-map (kbd "M-k") 'my-embark-M-k)

何もインストールしなくても2つとも実現できた機能かもしれないが、わたしには見つからなかったので自作してみた。

u/gusbrs

🔗

Votes 13

何年かmu4eを使ってみて、今では完全に虜である。しかしGmail(愛している訳ではないが節約の観点から数年来使用)のユーザーでもあることを客観的に見ると、いささかGmailへの偏重が過ぎるのではないだろうか。"Googleの次なる悪ふざけ"がわたしのワークフローを破壊するかもしれないことを、常に心配しなければならないのだ。mu4eを使用する上で学んだ大事な教訓はOrgとの統合である。org-captureのサポートによってInbox(受信箱)とTODOリストを混同せずに、Inboxを常にクリーンに保てるのだ。ブラウザのブックマークレットからGmailメッセージをキャプチャできる、org-protocolを活用するという予防策を考案してみた。特段綺麗なコードとは言えないが機能はする。

(with-eval-after-load 'org
  ;; Gmailでメールをキャプチャするorg-protocolを追加
  (add-to-list 'org-protocol-protocol-alist
               '("org-gmail-capture" :protocol "gmail-capture"
                 :function gb/org-protocol-gmail-capture))

  ;; Bookmarklet:
  ;;   javascript:location.href = 'org-protocol://gmail-capture?' +
  ;;       new URLSearchParams({
  ;;           msg: document.getElementById("raw_message_text").innerHTML});
  ;; "Original message"ページから呼び出さなければならない
  (defun gb/org-protocol-gmail-capture (info)
    "INFOとともにorg-protocol://gmail-capture形式のURLを処理する

この関数はGmailの"Original
message"ページから生のメッセージのテキスト要素を検出して、関係のあるメッセージフィールドを解析して、org-captureのテンプレート"email"を呼び出す

この場所へのブラウザのブックマークは以下のようになる:

  javascript:location.href = \\='org-protocol://gmail-capture?\\=' +
      new URLSearchParams({
          msg: document.getElementById(\"raw_message_text\").innerHTML});

The sub-protocol used to reach this function is set in
~org-protocol-protocol-alist'."
この関数に到達するためのプロトコルは`org-protocol-protocol-alist'にセットされている"
    (when-let* ((parts (org-protocol-parse-parameters info))
                (msg (plist-get parts ':msg)))
      ;; FIXME
      ;; これが何故必要なのか不明だが('org-capture'ロード前の)新鮮なセッション
      ;; だと新たなフレームが画面に一瞬表示されるだけでプロトコルが失敗する
      (require 'org-capture)
      (let (subj id to from date
            from-name from-email to-name to-email from-to-name)
        (with-temp-buffer
          (insert msg)
          ;; mu4eで新たなメッセージの閲覧/表示を担う'mu4e--view-render-buffer'
          ;; がデコード、フォント化等の処理を行う
          ;; ただしorg-protocolから受信するのは"オリジナル"というよりも
          ;; オリジナルをHTMLでレンダリングしたバージョンである
          ;; "Download original"というボタンもあるがGmailアカウントでログインした
          ;; ブラウザ専用なので表示されたページで何とかする必要がある
          ;; わたしたちが関心のあるフィールドという観点で考えるとバッファの整形
          ;; にはあまり意味がない
          (goto-char (point-min))
          (let ((case-fold-search))
            (while (re-search-forward
                    (rx
                     line-start
                     (group
                      (or
                       "From:"
                       "To:"
                       "Subject:"
                       "Date:"
                       "Message-ID:"))
                     " "
                     (group (zero-or-more not-newline))
                     line-end)
                    nil t)
              (pcase (match-string 1)
                ("From:" (setq from (match-string 2)))
                ("To:" (setq to (match-string 2)))
                ("Subject:" (setq subj (match-string 2)))
                ("Date:" (setq date (match-string 2)))
                ("Message-ID:" (setq id (match-string 2)))))))

        ;; 値の確認
        (when (or (not from) (string-blank-p from))
          (setq from "<none>"))
        (when (or (not to) (string-blank-p to))
          (setq to "<none>"))
        (when (or (not subj) (string-blank-p subj))
          (setq subj "No subject"))
        (unless date (setq date ""))
        (unless id (setq id ""))
        ;; フィールドのクリーンアップ
        (setq from (replace-regexp-in-string "&lt;" "<" from t t))
        (setq from (replace-regexp-in-string "&gt;" ">" from t t))
        (setq to (replace-regexp-in-string "&lt;" "<" to t t))
        (setq to (replace-regexp-in-string "&gt;" ">" to t t))
        (setq id (replace-regexp-in-string "&lt;" "" id t t))
        (setq id (replace-regexp-in-string "&gt;" "" id t t))

        (let ((addr (mail-extract-address-components from)))
          (if (car addr)
              (progn
                (setq from-name (car addr))
                (setq from (format "%s <%s>" (car addr) (cadr addr))))
            (setq from-name (cadr addr))
            (setq from (format "<%s>" (cadr addr))))
          (setq from-email (cadr addr)))
        (let ((addr (mail-extract-address-components to)))
          (if (car addr)
              (progn
                (setq to-name (car addr))
                (setq to (format "%s <%s>" (car addr) (cadr addr))))
            (setq to-name (cadr addr))
            (setq to (format "<%s>" (cadr addr))))
          (setq to-email (cadr addr)))
        (setq from-to-name
              (if (member from-email
                          '("myemail1@domain.com"
                            "myemail2@domain.com"
                            "myemail3@domain.com"
                            "myemail4@domain.com"))
                  to-name
                from-name))

        (let ((props `(:type "gmail"
                       :date ,date
                       :from ,from
                       :fromname ,from-name
                       :message-id ,id
                       :subject ,subj
                       :to ,to
                       :toname ,to-name
                       :annotation ,(org-link-make-string
                                     (concat "gmail:" id) subj)
                       :link ,(org-link-make-string (concat "gmail:" id))
                       :description ,(format "%s (%s)" subj from-to-name)
                       :annotation ,(concat "gmail:" id)))
              ;; `org-store-link'呼び出し回避('org-protocol-capture'を参照)
              (org-capture-link-is-already-stored t))
          (apply #'org-link-store-props props)

          (raise-frame)
          ;; Hard-coding the "e" capture template, since this function is very
          ;; much tailor made for it.
          ;; これはキャプチャテンプレート"e"に設えた関数なのでハードコーディングする
          (org-capture nil "e")))
      ;; 文字列をリターンしない('org-protocol-capture'を参照)
      nil))

  (org-link-set-parameters "gmail" :follow #'gb/org-link-gmail-open)
  (defun gb/org-link-gmail-open (link _)
    (kill-new (concat "rfc822msgid:" link))
    (message "Message id copied to clipboard.")))

これに対応するブックマークレットは:

javascript:location.href = 'org-protocol://gmail-capture?' + new
URLSearchParams({msg:
document.getElementById("raw_message_text").innerHTML});

これを"Original message"ページから呼び出さなければならない(メニューアイテム"Show
original"で取得できるだろう)。そこ以外から呼び出しても機能しないと思う。

作成されるgmail:タイプのリンクは基本的にはkillリング/クリップボードにrfc822msgid:<messageID>をコピーするだけである。これをGmailの検索バーに貼り付ければ、関心のあるメッセージに移動できるだろう。

それほど重要ではないが、これに相当するキャプチャテンプレート:

      ("e" "email" entry
       (file+headline (lambda ()
                        (expand-file-name gb/email-capture-file
                                          gb/org-files-directory))
                      "Email")
       "* TODO %?%:description %(org-set-tags \":email:\")
:PROPERTIES:
:Message: %a
:From: %:from
:To:   %:to
:Date: %:date
:END:
:LOGBOOK:
- Created on %U
:END:"
       :empty-lines 1)

u/[あぼーん]

🔗

Votes 13

orgマニュアルを読んでorg-agenda-category-icon-alistorg-agenda-prefix-formatという2つの変数を学んだ。前者はカテゴリ(CATEGORYプロパティ)にアイコン(イメージかシンボル)をセットする変数、以下はアジェンダをよりカラフルかつクリアーにするコードだ

(setq org-agenda-category-icon-alist nil)
(setq agenda-categories-alist
      '(("WORK" "💼")
        ("SOFTWARE" "💻")
        ("SETUP" "🐧")
        ("EMAIL" "✉️")
        ("HOME" "🏠")
        ("WOOD" "🪵")
        ("FAMILY" "👪")
        ("REPORTS" "📚")
        ("INCOME" "💰")))

(dolist
    (icon agenda-categories-alist)
  (add-to-list 'org-agenda-category-icon-alist
               `(,(car icon) ,(cdr icon) nil nil :width (16.) :ascent
center)))

(defun format-agenda-prefix ()
  (interactive)
  (setcar org-agenda-prefix-format '(agenda . " %-2i %?-12t% s")))

(add-hook 'org-agenda-mode-hook 'format-agenda-prefix)

emojiを正しく表示するためには以下を使用している:

(set-fontset-font "fontset-default" 'symbol (font-spec :family "Noto Color
Emoji"))

あなたたちはこれらのカスタマイズについてわたしよりたくさん知っていると思うので共有して欲しい

u/vatai

🔗

Votes 13

Emacsの真のチュートリアルは、実はEmacs Lispのチュートリアルのことなんだ ;)

u/WorldsEndless

🔗

Votes 13

ニュースサイトの有料コンテンツの壁や、Javascriptに貴院する不快事項をバイパスするためにEWWを使用できる。更に表示しているものをorg-modeと等価な構文にコピーできるし、速読用のSPLAYと互換性もある。言い換えると、インターネットを読むだけなら、EWWは素晴らしいツールだ。

u/emacs-noob

🔗

Votes 13

わたしはReact開発にEmacsを使っていて(rjsx-mode)、概ね快適に使えている。しかしわたしたちは最近スタイル付きコンポーネントをアプリに導入して、それはとても便利だがrjsx-mode内部に適切なcssサポートが存在しないのは非常に煩わしかった。わたしはrjsx-modeを拡張するような解決策を探したのだが解決には至っていない。しかしEmacsのビルトインのコマンドとバッファーで問題を解決できることに気づいたのだ!
わたしが求めていたのはスタイル付きコンポーネント内部のcssだが、これは常に以下のようなcssだ:

const myDiv = styled.div` // バッククォートに注目
    何かのcss...
` // バッククォート終わり

実際には scss-modeで編集して、完了したらrjsx-modeに戻る。elispはとてもシンプルであり、退屈なワークフローとなる:

;; 以下の2つの関数でscssモードの全機能を用いたスタイル付きコンポーネント編集が可能になる
(defun edit-styled-component ()
  (interactive)
  (progn
    (save-excursion
      (let ((start (search-backward "~"))
            (end (search-forward "~" nil nil 2))) ; second occurrence, since first is ~start'
        (narrow-to-region start end)))
    (scss-mode)))

(spacemacs/set-leader-keys-for-major-mode 'rjsx-mode
  "ms" 'edit-styled-component)

;; 編集完了で元のファイルにリターンするために同じキーシーケンスを用いる
(defun return-from-styled-component ()
  (interactive)
  (progn
    (widen)
    (rjsx-mode)))

(spacemacs/set-leader-keys-for-major-mode 'scss-mode
  "ms" 'return-from-styled-component)


これで", m
s"を押下するだけでバッククォートで括られたリージョンにナローイングしてスタイル付きコンポーネントを編集できるようになった。わたしのスニペット、補完等を用いて正真正銘のcssバッファーとして扱うことができる。編集が終わったら再度",
m s"を押下して、元の(rjsx-mode)のバッファーに戻れるのだ!

u/mullikine

🔗

Votes 13

ewwでchrome用のDOMを使う

最近では多くのウェブサイトがjavascriptを使用してDOMを生成している。chromeからダンプして、描画直前にewwに注入することも可能だ。

chromeがDOMをダンプするまで3秒待機するようにセットしてあるので、多くのページをロードできる筈だ。

わたしはunbufferプログラムを使っているので、システムにexpectがインストールされている必要がある。この方法でchromeが実行時にクラッシュしないように、以下ではttyを作成している。

  • シェルスクリプト: dump-dom
#!/bin/bash
    
url="$1" test -n "$url" || exit 1
    
0</dev/tty unbuffer bash -c "chrome --headless --disable-gpu
--virtual-time-budget=3000 --dump-dom \"$url\" 2>/dev/null"

eww-display-htmlには以下のような修正を施す。

  • eww-display-html
(defun eww-display-html (charset url &optional document point buffer encode)
  (unless (fboundp 'libxml-parse-html-region)
    (error "This function requires Emacs to be compiled with libxml2"))
  (unless (buffer-live-p buffer)
    (error "Buffer %s doesn't exist" buffer))
  ;; イメージの非同期ロードを中止するもっとましな方法がある筈だが
  (setq url-queue nil)
  ;; ドキュメントが存在すればhtmlはすでにDOMに解析済み
  (let* ((html (shell-command-to-string (concat "dom-dump " (shell-quote-argument url))))
         (document
          (or nil ;; ドキュメント
              (list
               'base (list (cons 'href url))
               (progn
                 (setq encode (or encode charset 'utf-8))
                 (condition-case nil
                     (decode-coding-region (point) (point-max) encode)
                   (coding-system-error nil))
                 (save-excursion
                   ;; 解析前にCRLFを削除
                   (while (re-search-forward "\r$" nil t)
                     (replace-match "" t t)))
                 (save-mark-and-excursion
                   ;; ここから終端までを削除して新たなhtmlに置き換える
                   (kill-region (point) (point-max))
                   (insert (encode-coding-string html 'utf-8)))
                 (libxml-parse-html-region (point) (point-max))))))
         (source (and (null document)
                      (buffer-substring (point) (point-max)))))
    (with-current-buffer buffer
      (setq bidi-paragraph-direction nil)
      (plist-put eww-data :source html)
      (plist-put eww-data :dom document)
      (let ((inhibit-read-only t)
            (inhibit-modification-hooks t)
            (shr-target-id (url-target (url-generic-parse-url url)))
            (shr-external-rendering-functions
             (append
              shr-external-rendering-functions
              '((title . eww-tag-title)
                (form . eww-tag-form)
                (input . eww-tag-input)
                (button . eww-form-submit)
                (textarea . eww-tag-textarea)
                (select . eww-tag-select)
                (link . eww-tag-link)
                (meta . eww-tag-meta)
                (a . eww-tag-a)))))
        (erase-buffer)
        (shr-insert-document document)
        (cond
         (point
          (goto-char point))
         (shr-target-id
          (goto-char (point-min))
          (let ((point (next-single-property-change
                        (point-min) 'shr-target-id)))
            (when point
              (goto-char point))))
         (t
          (goto-char (point-min))
          ;; フォーム内では通常のewwコマンドが利用できないので
          ;; フォーム内部にポイントを残さない
          (while (and (not (eobp))
                      (get-text-property (point) 'eww-form))
            (forward-line 1)))))
      (eww-size-text-inputs))))


ドキュメント: https://asciinema.org/a/UAAVfp5O8SofJZvKBusTOP8QQ

u/hmenke

🔗

Votes 13

BibTeXのユーザーいる?

  • ジャーナルのために記事のBibTeXレコード取得のためにファイルをダウンロードさせられるのにうんざりしていないだろうか?
  • それらのフォーマットが大抵壊れていることについては?
  • そもそもそのジャーナルはBibTeXのダウンロードを提供していないのか? (自分を振り返ってみて)

"doi.org"には記事のDOIで呼び出す際にBibTeXレコードを提供するクエリーインターフェイスがあることはご存知だろうか?
もちろんEmacsからアクセスできる:

(require 'url)
(defun user/url-bibtex-from-doi (doi)
  (interactive "sDOI: ")
  (let* ((url (concat "https://doi.org/" doi))
         (url-mime-accept-string "application/x-bibtex"))
    (insert
     (with-current-buffer (url-retrieve-synchronously url)
       (let* ((start url-http-end-of-headers)
              (end (point-max))
              (all (buffer-string))
              (body (buffer-substring start end)))
         (replace-regexp-in-string "^\t" "  " (url-unhex-string body)))))))

プロンプトに記事のDOIを貼り付けるだけで、ポイント位置にBibTeXレコードが挿入される筈だ。

わたしはbibtex-modeで以下のようにバインドしている(評価改善用に他のバインディングも定義している)

;; bibtex
(use-package bibtex
  :bind (:map bibtex-mode-map
              ("C-c d" . user/url-bibtex-from-doi)
              ("C-c v" . bibtex-validate)
              ("C-c s" . bibtex-sort-buffer)
              ([down-mouse-3] . imenu))
  :config
  (setq
   bibtex-maintain-sorted-entries t))

u/celeritasCelery

🔗

Votes 13

Emacsのshell-modeeshellのようなシェルでは、comint-accumulateを用いて複数行の入力を記述できる。これは通常だとC-c SPCにバインドされている筈だ。

u/NiceElk55

🔗

Votes 13

わたしはキーバインディングを見つけるのにwhich-keyパッケージを使っていたが、C-hについて学んで以来完全に使わなくなった。たとえばrectangle(矩形)のコマンドが使いたくてC-x rで始まることだけは覚えているが、それ以降はまったく覚えていないとしよう。C-x rの後にC-hをタイプするだけだ。これにより、そのプレフィックスキー配下のキーがすべて一覧されるだろう。M-sC-c等といった任意のプレフィックスキーで動作すると思われる。

関連事項としてはメジャーモード/マイナーモードのキーを調べる、C-h b(describe-bindings)が挙げられるが、利用できるキーバインディングおよびアクセント文字すべてを一覧するので使い物にならなかったが、Emacsの新たなバージョンではヘディングを折り畳めるので使いやすくなっている。

u/unduly-noted

🔗

Votes 13

macOSではショートカット(あるいはosascriptか)との統合で強力になり得る。わたしはレクチャー視聴時は左側にビデオ、右側にはノートを取るためのorg-modeを配置するのが好きだ。しかしビデオプレイヤーから頻繁にスクリーンショットをとって、org-modeやAnkiに貼り付けていることに気がついた。

ウィンドウのフォーカスに関わらずビデオプレイヤーを見つけて、クリップボードにスクリーンショットを取得するmacOSのショートカットを作成できた(重要なのはEmacsを離れる必要がない点だ)。これは極めて簡単に呼び出せる:
(call-process "shortcuts" nil nil nil "run" "IINA Screenshot").

このバインディングでビデオのスクリーンショット(org-downlod
)を簡単に貼り付けることができるようになった。ビデオを一時停止したりorg-modeを離れる必要さえなくなったのだ。Ankiにも簡単に貼り付けられる。この3行の関数によってわたしのワークフロー全体が円滑になったのである。

(defun me/iina-screenshot ()
  (interactive)
  (call-process "shortcuts" nil nil nil "run" "IINA Screenshot")
  (org-download-clipboard))

u/ImJustPassinBy

🔗

Votes 12

わたしが考え出した訳ではない。/u/arthurno1氏が考案した、diredwhich-keyを機能させる小技を共有させて欲しい(リンク先にスクショあり)。

https://www.reddit.com/r/emacs/comments/1clvkfe/announcing_casual_dired_an_opinionated_porcelain/l2yi5tn/

他のモードマップでも同じようにこのトリックが通用すると思う。

u/remillard

🔗

Votes 12

完全に記述した記事の投稿も考えたが、ここでは補助的なヒントの方が適しているだろう。いずれにせよ何らかのコードプロジェクトで作業している人なら誰でも、以前はTreemacsのヘビーユーザーだったこと、そしてそれが"project.el"に置き換えられていることに気が付くだろう。わたしがTreemacsを好んで使っていたのは、"Sublime
Text"や"VSCode"のファイル/プロジェクト用のサイドバーと似ているのが理由だった。それは一種の安心感による理由だろう。多くの事柄にたいしてdiredは良好に機能するが、Treemacsでネストされたディレクトリーをオープンする場合と比較して、大量のディレクトリーのナビゲーションは少々退屈に思えたからだ。

"project.el"を弄りだすきっかけすら思い出せない。誰かが記述したprojectへの切り替えに関する投稿だろうか。ともあれセットアップしてみて、それを使うことが苦痛ではないことが判ったのだろう。諸君、これは間違いなく良いアイデアだ。"project
goto file" (C-x p f)の便利さは尋常ではない。定義に応じて、あるいは2つのファイルを手早く切り替えられる、"ctags"をサポートするキーバインディングもあるのでプロジェクトを横断してシームレスにファイルを扱うことができる。projectがディレクトリーを探し出すのは、確認したい物事が格納されている場所に直接diredでアクセスするよりも高速だ。

ここでも補完が重い処理を大量に担っていることは想像に固くない。project.elが完全に初めてであればエクスペリエンスは異なるかもしれないが、今や非常に一般的に使用されている

ともあれわたしはここ数週間の間、Treemacsのサイドバーは開いていない。これがどんなに便利か興味がある人に何か書くべきだと感じたので、この記事を投稿した次第である。

u/geza42

🔗

Votes 12

意味的なハイライトにLSPサーバーを使っている場合には、font-lock-maximum-decorationの値をチェックしてみて損はないだろう。たとえばわたしはc++-modeとともにlsp-mode
(clangd)を使っているが、font-lock-maximum-decoration2に減らしてみたが、ハイライトに違いは認められなかった(c++-modeでハイライトされなくなった分はlsp-modeでハイライトされるため)が、c++-modeのフォントロックはより光速になった(c++-modeのフォントロックは99.9%の場合には良好に機能するもの、ときには遅くなる状況もあったものだがそれも解消されたようだ)。

わたしが使った設定: (setq font-lock-maximum-decoration '((c-mode . 2) (c++-mode . 2) (t . t)))

u/JDRiverRun

🔗

Votes 12

わたしは長いことorg-emphasizeのバインディングを、イタリックsuper-iのシステムのバインディングとして使ってきた。しかしいつもこれらがもっとスマートに、たとえばテキストを何も選択していないときでも使えるようにしたかった。たとえばポイントがすでに正しく強調されたテキストにあれ強調を賢く切り替えて、強調されていないときは単に強調するといった具合だ。

わたしの解決策を見て欲しい(下にスクロールすれば動きが確認できる)。他のあっicationではこの動作はサポートされていないだろうl!

u/ayyess

🔗

Votes 12

ミニバッファーを閉じると、ミニバッファーのオープン前に行ったウィンドウのレイアウト変更すべてが破棄されることへのわたしのフラストレーションを解決してくれたのが(setq read-minibuffer-restore-windows nil)だ。たとえばデフォルトではM-x C-h k k C-gはオープンしたヘルプバッファーだけを閉じる。わたしのQOLを改善するこんなネタを、NEWSから今までどれだけ見逃していたのだろう。

u/elevencupfuls

🔗

Votes 12

ビルトインのElispファイルに挑戦してみて、如何に多くの物事がどのように動作しているかについて知見を得ることができた。インデントにたいしてはGNU標準があり、アラインメントにタブとスペースを混ぜて使用するように定められているらしい。アラインメントが機能するためにはタブが8個のスペースとして描画される必要があるのだが、他のどこかでそのセッティングを実際に使いたいと思うことはないだろう。Mac上のファイルはアプリケーションのバンドル内部にあるので、ファイルの場所に".dir-locals.el"を置くのも躊躇われる。

そんなときはディレクトリークラス(Directory
classes)
が助けになる!
わたしはコンフィグでディレクトリー変数クラスを新たに作成した。これはemacs-lisp-modetab-widthに8を使うことを指示するリストだ。そしてアプリケーションにバンドルされているElispファイルにそのクラスを適用した:

(use-package elisp-mode
  :config
  (dir-locals-set-class-variables
   'builtin-elisp
   '((emacs-lisp-mode . ((tab-width . 8)))))
  (dir-locals-set-directory-class
   (file-name-directory (directory-file-name (invocation-directory)))
   'builtin-elisp))

そうしたらそれらのファイルのいずれかをvisitした際のアラインメントが常に正しく表示されるようになった。

u/[あぼーん]

🔗

Votes 12

Org mode - エクスポートオプションの完全なセットを挿入する方法:

org-export-insert-default-template

これは行頭にすべてのエクスポートキーワードとそれのデフォルト値を挿入する。

このコマンドはinfo emacs (v27.1)にはドキュメントされていない。

u/b3n

🔗

Votes 12

洒落たeshellコマンドを1つ:

(defun eshell/history ()
  (interactive)
  (insert
   (completing-read "History: " (delete-dups (ring-elements eshell-history-ring)))))

これは通常の補完フレームワークを使ってヒストリーからアイテムを検索できる。突然fzf風のヒストリーになるだろう!

u/rhmatthijs

🔗

Votes 12

教育に従事していると、学生をグループに割り当てることが頻繁にあると気づいた。これを行う助けとなる関数を今週作成した。学生(とか)のリストを含んだバッファーのリージョンを選択してこの関数を呼び出し、グループそれぞれに学生は何人か告げるとランダムにグループを割り振るのだ。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; シャッフル                                                   ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
(defun mcj/shuffle (input)
  " リスト自体をFisher-Yatesでシャッフル(デフォルトでは何故か存在しない)
"
  (let ((swap (lambda (list-to-swap i1 i2)
                (let ((tmp (elt list-to-swap i1)))
                  (setf (elt list-to-swap i1) (elt list-to-swap i2))
                  (setf (elt list-to-swap i2) tmp)))))
    (dotimes (i (length input) input)
      (funcall swap input i (random (+ i 1))))))

    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; オブジェクト(たとえば学生をペアリング                        ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
(defun mcj/pair-off (input num)
  "inputの要素を長さnumのペアにしてリターンする"
  (cond ((< (length input) (* num 2)) (list input))
        (t
         (cons (butlast input (- (length input)num)) (mcj/pair-off (nthcdr num input) num)))))
    
    
    
(defun mcj/pair-off-region (num)
  " リージョン内の行をペアリング"
  (interactive (list
                (read-number "Members per pair (num):" 2)))
  (let ((newcontents
         (mapconcat (lambda (item-pair)
                      (mapconcat (lambda (item) item) item-pair " + "))
                    (mcj/pair-off
                     (mcj/shuffle
                      (split-string
                       (buffer-substring-no-properties (mark) (point)) "[\n]" t ))
                      num)
                    "\n")))
    (delete-region (mark) (point))
    (insert newcontents)))

u/hale314

🔗

Votes 12

わたしにはフックに追加するために、多くの関数を単独で定義する傾向がある。しかしdefun-declarations-alistをカスタマイズすれば、declareフォーム内に新たなhookプロパティを定義できるのだ。これでその関数の定義内で、その関数が意図しているフックを指定できるようになった。

;; 関数がコンパイルされる場合にはコンパイル中に実行する必要あり
(eval-and-compile
  (setf (alist-get 'hook defun-declarations-alist)
        (list (lambda (fun _args hook &optional depth)
                `(add-hook ',hook #',fun ,@(when depth (list depth)))))))
    
(defun ask-about-scratch-buffer ()
  "scratchバッファーの内容を破棄してよいかユーザーに確認を求める"
  (declare (hook kill-emacs-query-functions))
  (let ((scratch (get-buffer "*scratch*")))
    (or (zerop (buffer-size scratch))
        (progn (pop-to-buffer scratch)
               (y-or-n-p "Scratch buffer is not empty, discard?")))))
;; もう不要
;; (add-hook 'kill-emacs-query-functions #'ask-about-scratch-buffer)

u/ImJustPassinBy

🔗

Votes 11

別々のEmacsフレームをそれぞれ個別のモニターに表示してよく作業するが、それらのフレーム間の切り替えにはframemoveが最高だ。windmoveにフックインして(切り替えるウィンドウがなければウィンドウ調節がフレーム調節に切り替わることを意味する)、以下の関数が利用できる:

  • fm-up-frame: カレントフレームの上のフレームを移動
  • fm-down-frame: カレントフレームの下のフレームを移
  • fm-left-frame: カレントフレームの左のフレームを移動
  • fm-right-frame: カレントフレームの右のフレームを移動

主要なパッケージレポジトリではどこも扱っていないので、手作業でインストールする必要がある。emacsmirror,のおかげで、use-packagestraightでもインストールできる(バインディングはお好みで):

(use-package framemove
  :straight (:host github :repo "emacsmirror/framemove")
  :init
  (setq framemove-hook-into-windmove t) ;; :configや:customでは機能しない
  :bind
  (("C-x 5 <up>" . fm-up-frame)
   ("C-x 5 <down>" . fm-down-frame)
   ("C-x 5 <left>" . fm-left-frame)
   ("C-x 5 <right>" . fm-right-frame)))

編集:
唯一理解できないのが、なぜ:config:customframemove-hook-into-windmovetをセットしても機能しない点だ。パッケージがロードされてC-h ffm-up-frameの存在は確認できるが、C-h vframemove-hook-into-windmoveが見つからないのだ。fm-up-frameの実行後にはframemove-hook-into-windmoveは見つかるもの、tではなくnilにセットされている。

u/sauntcartas

🔗

Votes 11

何年か前に今の職に就いたときにorg-captureを使い始めた。以下のテンプレートで日々のアクティビティを記録するのだ:

(setq org-capture-templates
      '(("d" "Done" entry (file+olp+datetree "~/org/done.org"))))

少し気にくわないのorg-captureを呼び出したファイル位置への意図しないリンクが、ログエントリーとともに保存されることだった。これをなくすために何年かの間、不定期に気まぐれな努力を費やしたものの、解決には至らなかった。最近ようやくより秩序だった取り組みを行い、org-capture-templates変数用のドキュメントを熟読して最終的な解決策を導き出すことができた。キャプチャタイプentryにたいするデフォルトのテンプレートは"* %?\n%a"だが、ここで%aは"annotation(注釈)"、つまりファイル位置へのリンクを意味するコードだったのだ。つまり以下のように定義を変更する必要がある:

(setq org-capture-templates
      '(("d" "Done" entry (file+olp+datetree "~/org/done.org") "* %?")))

u/UsualOffice1740

🔗

Votes 11

マクロを使い始めた。素晴らしい。以下わたしの小技。記録の終了はC-x -(、開始がC-x-)。最後に記録したマクロの実行はF4。開始は常に行頭から。移動は常に単語か行単位。2文字前進、次行で3文字前進させるマクロは動作しない。常に行頭にリターン。次行にイカした方法で移動するためにマクロを再利用するよう自分を仕向ける。

u/bopboa

🔗

Votes 11

何もパッケージをインストールせずにビーコンを得る方法。

(defun pulse-line (_)
  (pulse-momentary-highlight-one-line (point)))
(setq window-selection-change-functions '(pulse-line))

u/algor512

🔗

Votes 11

C-h C-q (or M-x help-quick)をタイプすると一部の基本的なキーバインディングをわかりやすくまとめた、*Quick Help*バッファーを表示する小さなウィンドウがオープンすることに最近気づいた。このバッファーのコンテンツは、help-quick-sectionsという変数を通じて設定されるらしい。

わたしがいつもど忘れしがちなめったに使わないキーバインディングの覚書として、チートシートのように使うつもりだ。help-quick-sectionsの値を変更することで、簡単に状況依存なヘルプでできる筈だ。

u/camelcaset

🔗

Votes 11

これはEmacsというよりmacOSの小技かもしれない。C-fC-b等は任意のテキストボックスで機能する。M-f等はそのように機能してくれないが、これはOSで簡単に変更できることが判ったのだ!

以下のようなファイルを作成して以来、どこでもEmacsのキーバインディングが使えるようになった:

/* ~/Library/KeyBindings/DefaultKeyBinding.dict */
{
    /* Additional Emacs bindings */
    "~f" = "moveWordForward:";
    "~b" = "moveWordBackward:";
    "~<" = "moveToBeginningOfDocument:";
    "~>" = "moveToEndOfDocument:";
    "~v" = "pageUp:";
    "~d" = "deleteWordForward:";
    "~^h" = "deleteWordBackward:";
    "~\010" = "deleteWordBackward:";  /* Option-backspace */
    "~\177" = "deleteWordBackward:";  /* Option-delete */
}

もっと多くのキーバインディングも見つかる筈だ:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/EventOverview/TextDefaultsBindings/TextDefaultsBindings.html

u/leothrix

🔗

Votes 11

elisp を弄っているち、リストから要素を1つ削除したい場合がないだろうか?

completion-at-point-functionsのようなフックや変数にたいして要素の追加や削除を行う際には、追加したシンボルを少々弄る必要があることが多い。どこかで何らかのフォームを評価することもできるが、わたしは単にズボラに以下で済ませる方が好みだ:

M-x remove-hook

そうすればlist風の変数すべてから任意の要素を削除するための、(completing-readを用いた)対話的なインターフェイスが手に入るだろう。これは技術的にはフックの変更を意図しているが、リスト関係なら何でも悪用できるのだ。

u/tryptych

🔗

Votes 11

今ではEmacsでも長い行のサポートも改善されただろうか??

NEWSで最近追加されたものを見ていて気がついたのだ:

Emacsで任意の長さの行を編集する能力が改善された。長い行の表示の最適化により、表示中のバッファーに長い行が含まれているせいでEmacsが固まることはなくなったのだ。それでもまた長い行を含んだファイルの編集中にEmacsの低速化が認められる場合には原因はフォントロックにある。フォントロックをM-x
font-lock-mode(またはC-u C-x x
f)でオフにするか、あるいはカレントのメジャーモードや有効になっているマイナーモードのいずれかをオフにしてみて欲しい(C-x C-fではなくM-x
find-file-literallyでファイルをオープンする)。これらの表示最適化がいつどこで使用されるかを制御する変数は'long-line-threshold'だ。

素晴らしいニュースに思える! わかる人いる?

(追記: 今週のどこかで追加された機能だ。毎週行っているmasterをビルドして、NEWSのdiffは毎回チェックしている)

u/yogsototh

🔗

Votes 11

わたしが優れたEmacsパッケージと個人的なテーマを組み合わせたのは、iAWriterのクールな効果を実現するためだ。

https://her.esy.fun/posts/0021-ia-writer-clone-within-doom-emacs/index.htmlを参照のこと。

u/PotentiallyAlice

🔗

Votes 11

わたしが趣味で作っているのはorg-captureテンプレートをエンドポイントとすることによって、ネットワーク上の他のデバイスからメモをTODOに追加するパッケージだ。パッケージというほどのものではなかった:

(defservlet* capture/:keys/:contents text/plain () (org-capture-string
contents keys))

これで"localhost:8080/capture/t/test reminder"とタイプすれば、"todo.org"に"* TODO test
reminder"という行が挿入されるようになった。合格だ!

u/jumpUpHigh

🔗

Votes 11

AucTeX

TeXファイルのコンパイルでエラーが発生したら、以下のコマンドでエラーメッセージを確認するように求められるだろう

C-c ~

これにより理解不能な最後のエラーに導かれて、何が悪いか解決する破目に陥ることがままある。

以下の変数をtにセットすれば、最後のエラーではなくすべてのエラーの概要を得られる筈だ:

(setq TeX-error-overview-open-after-TeX-run t)

以下を使えば別フレームにポップアップ表示できる:

(setq TeX-error-overview-setup 'separate-frame)

関連する文書についてはリンク先を参考にして欲しい。

これによってエラーメッセージの処理全体が一変するだろう。

u/kastauyra

🔗

Votes 11

コンフィグを26.3から27.1に以降した。フレームがフォーカスを失った際のGCへの微調整が盛り込まれている(お手本はMatthewZMD氏のコンフィグだったと思う:

(add-hook 'focus-out-hook #'garbage-collect)

27.1のNEWSにはより一般的(そして正確)に、かわりにafter-focus-change-functionを使うように記載されている。あるフレームがフォーカスを受け取る際には、フォーカスのないフレームすべてのGCを無効にしたいというのがわたしの意図だ。最終的にどのフレームもフォーカスを受け取らなければ、GCというのもよいだろう。驚いたことにコピペを目論んでいた公開されているdotファイルにはこれを実装したものが見つからなかったので、自分での記述を試みたという訳だ。

(defun dotfiles--gc-on-last-frame-out-of-focus ()
  "すべてのフレームのGCを非アクティブにする"
  (if (seq-every-p #'null (mapcar #'frame-focus-state (frame-list)))
  (garbage-collect)))

(add-function :after after-focus-change-function
          #'dotfiles--gc-on-last-frame-out-of-focus)

u/sauntcartas

🔗

Votes 11

M-|
(shell-command-on-region)を何年か頻繁に使ってきたが、使用するリージョンをアクティブにする必要はないという事実は知らなかった。リージョンがアクティブでなければ、コマンドはポイント位置からバッファー終端までのテキストを処理するのだ。この動作は合理的であり他のコマンドにも採用されている動作だが、ドキュメントには記載されていなかったので試したことがなかった。

バッファー全体を処理したいときのほとんどに実行しいていたC-x h
(mark-whole-buffer)が不要になった。シェルコマンドを構築する際にバッファー全体がハイライトされるのが少々目障りだったのだが、この点も解決された。

追記: これではわたしが期待したように動作しないらしい。詳細については以下のコメントを参照して欲しい。

u/jimm

🔗

Votes 11

わたしは単語の補完にdabbrev-expand (M-/)を使った回数を覚えているだろうか。とてつもない時間を節約してくれた。

u/ImJustPassinBy

🔗

Votes 10

最近見つけたorg-pdftoolsなら、EmacsでPDFに注釈をつけたいというわたしの要件を満たしてくれる。主に組み込み関数org-store-linkの強化に使用している:

  • PDFの一節をマークしたらM-x org-store-linkを実行すると、そのPDFにハイライト(技術的には空の注釈)を作成して、それ用のリンクをコピーする-
    任意のorgバッファーでC-c C-lを実行すればコピーしたリンクを貼り付けて名前の入力を求める

インストールは簡単だ。org-modeにフックを仕掛けるだけである:

(use-package org-pdftools
  :after (org pdf-tools)
  :hook (org-mode . org-pdftools-setup-link))

orgバッファーのリンクを削除しなければPDFのハイライトは自動的に削除されないことだけ覚えておけばよいだろう。これはPDFから手作業で行う必要がある(C-c C-a lで全ハイライトを一覧、Dで削除だ)。

これはorg-noter,に機能は少ないが、こちらの方が柔軟なのでわたしのユースケースにより適合するのだ。残念ながらorg-noterと依存関係にあるので最終的にはロードされると思うが。

u/ilemming

🔗

Votes 10

varsを使えば以下のようにしてorgソースブロックに値を指定できるのは承知だろう:

#+begin_src bash :var token="bla-bla-bla"
echo ${token}

#+RESULTS:
  : bla-bla-bla

これを使えばあるブロックから別のブロックにデータを渡せることについても大丈夫だろうか?別のブロックの結果に基づいて何かを計算する必要がある場合には、ブロックに名前をつければよいのだ。

#+name: dirs #+begin_src bash :results silent
ls
#+end_src

#+begin_src js :var data=dirs
console.log(data)

\#+END<sub>SRC</sub>

だがそこでelispも使えることは知っていただろうか?

#+begin_src js :var data=(if (featurep :system 'macos) "🍎" "🐧")
return data;
#+end_src

#+RESULTS:
: 🍎

\#+END<sub>SRC</sub>

前の例に似せてdirsを使うが、追加のソースブロックは不要だ:

#+begin_src clojure :var data=(shell-command-to-string "ls -a ~")
;; すべてのdotファイル
(require '[clojure.string :as str])

(->>  (str/split data #"\n")
      (filter (partial re-find #"^\.*"))
      (sort)
      (str/join "\n"))

#+END<sub>SRC</sub>

u/fuzzbomb23

🔗

Votes 10

initファイルの管理でお気に入りの1つが、use-packageimenuサポートだ。でもデフォルトではオフなのだ:

(setq use-package-enable-imenu-support t)

優れたimenuのUI(たとえばconsult-imenuとVertico)と組み合わせれば、initファイルでのナビゲーションが本当に早くなるだろう。

u/wintershere

🔗

Votes 10

言語のヘッダのクォートをエスケープしてエクスポートするorgファイルの<html>タグに属性を追加するシンプルなハック。

#+HTML_DOCTYPE: html5 #+LANGUAGE: en" data-theme="dark

これをorg-html-export-to-htmlでHTMLにエクスポートすると:

<html lang="en" data-theme="dark">

<html>タグに直接属性を追加する必要がある、一部のクラスレスCSSライブラリーを含める際に役に立つだろう。

xml:langのために余分に1つ追加されて属性が重複するので、HTML_DOCTYPEは省略しないこと。

u/saltwaterflyguy

🔗

Votes 10

describe-*、これはEmacsに存在するほぼすべてのドキュメントにアクセスするための、もっとも便利な機能の1つだ。あるモードでセットされるキーバインディングが判らない?
M-x describe-modeC-h mだ。特定のテキストに使用されているフォントが知りたい? M-x describe-charだ。コマンドの機能が知りたい? M-x describe-commandC-h xだ。変数なら? M-x describe-variableC-h vだ。

Emacsを使うのが初めてなら、すべてのdescribe関数を知っておくだけで解答の多くを入手できるだろう。

u/[あぼーん]

🔗

Votes 10

あなたたちの多くはすでに知っているだろうが、"インダイレクトバッファー(indirect buffers)"は役に立つことに気づいた。

lVimユーザーだった頃にはバッファーを2つのウィンドウに分割して、コードの折り畳みを使って同じファイルの別の部分を2つのウィンドウで見比べるのが役に立った。しかしVimとは異なりEmacsではバッファーの"folding(折り畳み)"と"narrow(絞り込み)"の状態がウィンドウ間で同期されているのだ。具体的なユースケースとしては、ある巨大なOrgファイルがあり、異なるヘディングにたいしてC-x n sでナローイングして、それを個別のウィンドウに表示したい場合だ。

これを解決したのがインダイレクトバッファーなのだ。インダイレクトバッファーなら1つのファイルに2つのバッファーを割り当てて、それらにたいして個別にフォールディング、ナローイング等をセットすることができる。しかしファイルの内容は依然として同期されたままなので、別バージョンのファイル状態が生まれる危険もない。わたしが行いたいことは、デフォルトではC-x 4 c C-x n sにバインドされていたのである。

u/badmaxton

🔗

Votes 10

embarkのコンフィグの:initセクションに以下を追加するだけ:

(define-key minibuffer-local-map [C-tab] 'embark-select)

これは後でembark-allするエントリーをマークにembarkメニューを経由するかわりに、C-TAB(デフォルトではfile-cache-minibuffer-completeにバインドされているが使ったことがない)でマークできるようにして使いやすくしている。

u/gusbrs

🔗

Votes 10

今日は古い.odtのノートファイルを.orgに変換したのだが、その際にセンテンス単位で正しくナビゲーションできるように、センテンス終わりのピリオドの後に2つのスペースを追加したかった。なので十分汎用性のあるregexpを何回目だったかにひねり出して、最終的にはそれをメモしていなかったことを後悔することになった。今度こそよいregexpを見つけたら書き写しておくことに決めた。誰かによって共有されていたregexpだったことは明らかだったからだ。そしてEmacsがわたしが全然聞いたこともない、repunctuate-sentencesを提供していることが判ったという訳だ。新しいのか、それとも前から常に存在していた関数なのか判らない。わたしにとっては新登場の関数だ。この関数が用いているのはquery-replace-regexpであり、エクスペリエンスも同じである。repunctuate-sentences-filterを使えば除外対象も設定できる。解決だ!

u/sauntcartas

🔗

Votes 10

日々の業務として複数のGitレポジトリで作業しているが、そのうちの1つの作業がわたしの時間の95%を占めていた。どのレポジトリにもいないときにコマンドのいずれかを実行したときには、あたかも最初からメインのレポジトリでコマンドを実行したかのようにProjectileを設定できないものかと感じていた。これを行うビルトインの手段は見つからなかったが、いくつkのadviceによって望んだ効果を得ることができた:

(defun default-to-main-project (dir)
  (or dir *main-project-dir*))

(advice-add 'projectile-ensure-project :override #'default-to-main-project)

projectile-ensure-projectの機能のうちのいくつかを失うことになったが、いずれにせよ使ったこともない機能だ。

u/slinchisl

🔗

Votes 10

小さな関数への代替え案の選択用に、ユニバーサル引数に優るインターフェイスとしてのread-keyの有用性を再度思い出させてもらった。これはオプションとしてプロンプトを受け取り、キーボードから読み取ったキーをシンプルにリターンするだけの関数である。

たとえば事前定義した日付セットをカレントバッファーにプリントする関数が欲しかったのだが、以下のように簡単に実現できるのだ

(defun slot/insert-time ()
  (interactive)
  (let* ((formats '((?i "ISO 8601"  "%Y-%m-%d")
                    (?l "DDmmmYYYY" "%d%b%Y")
                    (?t "Time"      "%H:%M")))
         (key (read-key
               (cl-loop for (key label _) in formats
                        concat (format "[%s] %s "
                                       (propertize (single-key-description key) 'face 'bold)
                                       label)))))
    (->> (alist-get key formats)
         cl-second
         format-time-string
         downcase                     ; Jan -> janに小文字化
         insert)))

u/[あぼーん]

🔗

Votes 10

スペースの隣りにコントロールキーを配置してMacのコマンドキーを模倣する(実質的にCTRLと等価だがSPCの隣りにある方がタイプしやすい)

Win - Alt - Ctrl - Space - Ctrl - Alt - Win

u/AnugNef4

🔗

Votes 10

M1 Macで/opt/homebrew配下にあるインストール済みの".info"ファイルすべてを、C-h iのInfo
Directoryノードに表示する方法について。
How I got my Info Directory node to display all my installed files living
under on an .
わたしが実行しているのは、Githubのd12frostedから取得した"emacs-plus@29"だ。

"init.el"からのスニペット

(require 'info)
(info-initialize)
(push "/opt/homebrew/share/info" Info-directory-list)

Directoryノードの更新には以下のシェルスクリプトを実行する。

#!/usr/bin/env bash
    
INFO_DIR="/opt/homebrew/share/info"
while read -r f; do
    install-info --debug --keep-old "$f" "$INFO_DIR"/dir
done <<< $(find /opt/homebrew/Cellar -name \*.info)

u/oantolin

🔗

Votes 10

何か区切り文字で選択したリージョンを括るキーバインディングは如何だろう? ビルトインの解決策:

(defvar insert-pair-map
  (let ((map (make-sparse-keymap)))
    (define-key map [t] #'insert-pair)
    map))

(global-set-key (kbd "C-S-w") insert-pair-map)

これはC-S-wでプレフィックスマップinsert-pair-mapをセットアップするスニペットだ。insert-pair-mapで唯一のキーバインディングは[t]である。つまりこれがデフォルトのキーバインディングであり、プレフィックスキーの後のキーはすべて同じコマンドinsert-pairを実行するのだ。insert-pairは呼び出しに用いられたキーを調べて、それがオープン区切りであれば対となるクローズ区切りとともに挿入する(リージョンがアクティブならリージョン先頭にオープン区切り、リージョン終端にクローズ区切りを挿入してリージョンを括る)。

u/andyjda

🔗

Votes 10

god-modeを使い始めたが、どのキーシーケンスがどのコマンドをトリガーするか簡単にチェックする方法がないので、最初はそれに苦労した。

わたしはgod-modeのキーシーケンスをコマンドに変換して、そのコマンドをdescribeした結果を表示するgod-mode固有のdescribe-keyを記述した。パッケージがキーを扱う方法に親しむ方法としては素晴らしい方法だと思う。そしてこれはgod-modeを抜け出さずにユーザーがdescribe-keyを呼び出せるようにできるのだ(以前はほとんどのキーにたいしてgod-mode-self-insert-commandに関する一般的な情報が表示されるだけだった)。

パッケージのメンテナにも連絡して、この機能(微調整後)はmasterブランチにも追加された。god-modeのコードや挙動が身近になるには素晴らしい体験だったし、初めてEmacsパッケージに貢献できて幸せだ。

u/kickingvegas1

🔗

Votes 10

Orgテーブルで作業時にはS-RETで上のセルの値をカレントセルに挿入できる。https://lists.gnu.org/archive/html/emacs-orgmode/2010-03/msg00462.html

u/ainstr

🔗

Votes 10

先日dbus経由でSpotifyにアクセスできることを発見した。わたしのSpotifyのユースケースは、自分のプレイリストから20曲くらいまでをシャッフルほとんどで検索、Discovering、チャート等はほとんど使っていない。したがって追加の認証トークンや余っているローカルサーバーを必要とする既存パッケージは何も必要ではない。

以下は基本的にはspotify-playlistsに格納しらalistをcompleting-readでラップしたものだ。qdbus呼び出しはdbus-sendとかに変更できるだろう。

;; sp.sh: https://gist.github.com/wandernauta/6800547に発想を得た
;; https://codeberg.org/jao/espotifyも使えたがすべての機能が必要という訳ではない
;; 潜在的な問題点:
https://community.spotify.com/t5/Desktop-Linux/DBus-OpenUri-issue/td-p/1376397
    
;; IDを抽出してspotify-playlistsで使用するfnの記述でも可
;; 現時点では完全なURIを使っているのでプレイリスト/アーティスト等の比較も可
;; しかしわたしのユースケースでは柔軟性は必要ない
(defun spotify--clean-uri (raw-uri)
  "Clean RAW-URI into a dbus-acceptable uri."
  (let* ((url-fields (split-string
		      raw-uri
		      (rx (or "/" "?"))))
	 (type (nth 3 url-fields))
	 (id (nth 4 url-fields)))
    (concat "spotify:" type ":" id)))
    
(defvar spotify-playlists
  '(("Artist" . "https://open.spotify.com/playlist/1v4UqI9mEEB4ry3a3uaorO?si=bc675402c7384080"))
  "選択先となるspotify-playlists用のSpotifyプレイリストのalist
  RAW-URIはプレイリストを右クリック > Share > Copy Link to Playlist.で取得している)
    
(defun spotify--open-uri (raw-uri)
  "RAW-URIをオープン"
  (let ((prefix "qdbus org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.OpenUri ")
	(uri (spotify--clean-uri raw-uri)))
    (shell-command (concat prefix uri))))
    
(defun spotify--open-playlist ()
  "spotify-playlistsから再生するプレイリストの選択を求める"
  (let* ((key (completing-read "Playlist: " spotify-playlists))
	 (raw-uri (cdr (assoc key spotify-playlists))))
    (spotify--open-uri raw-uri)
    (message (format "Now Playing: %s" key))))
    
(defun spotify-open-playlist ()
  "Wrapper around ~spotify--open-playlist~, to check if spotify is running."
  "Spotify実行中かをチェックする`spotify--open-playlist`のラッパ"
  (interactive)
  (pcase
      (shell-command "pgrep spotify")
    (1 (message "Spotify not running."))
    (0 (spotify--open-playlist))))

u/char1zard4

🔗

Votes 10

今週学んだこと:

  • yes/noプロンプトすべてをy/nプロンプトに再定義できる:

(defalias ‘yes-or-no-p ‘y-or-n-p)

  • LaTeX-modeバッファーでのC-c C-cで出力のコンパイル/出力の閲覧ができる(これまで数年間はLaTeX-preview-paneを使っていた)

  • yas-snippetTABストップはテンプレートの複数部分を充填するのに非常に便利(存在すら知らなかった:

https://joaotavora.github.io/yasnippet/snippet-development.html#org41a4ac7

u/[あぼーん]

🔗

Votes 10

[あぼーん]

u/jimm

🔗

Votes 10

gitコマンドgit grepはgitレポジトリ内のすべての場所からregexp(単なる文字列も可)を見つけられる優れもの。以下の関数を定義してgit-grep関数をF2にバインドした。regexpの入力を求めてレポジトリを検索したり、C-uのように数プレフィックスを与えればポイント位置のシンボル(カーソルの下にある単語)を読み取って検索する。結果はgrep
バッファーに表示されるので、C-g C-nC-g C-pで結果の間をナビゲーションできる。

(defun git-root-dir ()
  "カレントディレクトリのルートGitレポジトリをリターンする
カレントディレクトリがGitレポジトリでなければNIL"
  (let ((dir (locate-dominating-file default-directory ".git")))
    (when dir
      (file-name-directory dir))))
    
(defun git-grep (arg)
  "カレントディレクトリのgitレポジトリのルートディレクトリから
'git grep'コマンドを実行する
    
デフォルトではミニバッファーからregexpを読み取る
プレフィックス引数を指定するとポイント位置の
カレントシンボルで検索文字列を初期化する"
  (interactive "P")
  (let* ((symbol-at-point (thing-at-point 'symbol))
         (regexp (if (and arg (symbol-at-point))
                   (regexp-quote symbol-at-point)
                     (read-from-minibuffer
                      "Search regexp: " nil nil nil 'grep-find-history)))
    
         (default-directory (git-root-dir))
         (case-ignore-flag (and (isearch-no-upper-case-p regexp t) "-i"))
         (cmd (concat "git grep --extended-regexp --line-number --full-name"
                      " --untracked " case-ignore-flag " -- \"" regexp "\""
                      " | cut -c -240")))
    (while (equal "" regexp)
        (setq regexp (read-from-minibuffer
                      "Search regexp (must not be the empty string): " nil nil nil 'grep-find-history)))
    (grep-find cmd)))

u/shitterwithaclitter

🔗

Votes 10

上端のsrcブロックには簡単にelispスニペットを記述できる状態のままorg-modeでEmacsを開始するというアイデアを得た。関心のある誰かのために:

;; lisp評価用のソースブロックがあるorg-modeを開始する
(setq initial-major-mode #'org-mode
      initial-scratch-message
      "#+begin_src emacs-lisp\n;; これは保存されないLisp評価するテキスト用のブロック\n;; ファイル作成は[find-file]でvisitしてそのバッファにテキスト入力\n\n#+end_src\n\n")

u/WorldsEndless

🔗

Votes 10

Emacsのマクロはまるで失われた秘密の芸術と似ているが、わたしはregexp検索やorg-modeコマンドの繰り返しイベントの微調整(他にもさまざまな用途)に使用している。マクロを学ぼう。Emacsという名前の由来だ!
使い方の1つはここに記載されている: https://orys.us/ug

u/SamTheComputerSlayer

🔗

Votes 10

わたしはコンフィグで多くの切り替え(toggle)を行っている。以前は毎回即興的に行っていたのだが、最終的には1つのパターンに帰結するのでマクロ化した:

(defun deftoggle-var-doc (name)
  (concat name "が有効なら非nil\n\n"
      "何をtoggleするかは" name
      " コマンドを参照のこと"))
(defun deftoggle-fun-doc (name doc)
  (concat "Toggle " name " on or off.\n\n" doc))
(defmacro deftoggle (name doc enabler disabler)
  `(progn
 (defvar ,name nil ,(deftoggle-var-doc (symbol-name name)))
 (defun ,name (&optional enable)
   ,(deftoggle-fun-doc (symbol-name name) doc)
   (interactive)
   (if (called-interactively-p 'interactive)
       (progn
         (if ,name
             ,disabler
           ,enabler)
         (setq ,name (not ,name)))
     (progn
       (if enable
           ,enabler
         ,disabler)
       (setq ,name enable))))))

define-minor-modeとよく似ているがすべてのフック、キーマップ、ハイライトは削ぎ落とされているので無駄がない。たとえば以下はテーマの切り替えに使っている例だ:

(deftoggle sam-toggle-theme
  "テーマのlight/darkを切り替え"
  (progn (disable-theme 'dracula)
     (load-theme 'spacemacs-light t))
  (progn (disable-theme 'spacemacs-light)
     (load-theme 'dracula t)))

u/[あぼーん]

🔗

Votes 10

evilをロードする前にミニバッファーでevil-modeを使うには(setq evil-want-minibuffer t)とすればよい。

u/github-alphapapa

🔗

Votes 10

わたしにとってもっとも役に立つコマンドの1つ:

(use-package avy
  :bind* (("C-j" . avy-goto-char-timer)))

u/Stefan-Kangas

🔗

Votes 10

SICPを読む。Infoが望ましい。MELPAからインストールするかhttps://github.com/webframp/sicp-infoで入手できる。

u/Stefan-Kangas

🔗

Votes 10

count-words-regionにたいするバインディングをcount-wordsに置き換える。後者はリージョンがアクティブならリージョン内の単語だけ表示するので意味的に優る。

(global-set-key (kbd "M-=") #'count-words)

u/dmartincy

🔗

Votes 10

Emacsには昔からLispを記述する際に、カッコの釣り合いを保ちつつコードを記述する助けとなるようなコマンドとしてM-(
(insert-parenthesis)とM-)
(move-past-close-and-reindent)がある。以前はEmacsマニュアルに文書化されていたのだが、おそらく他の文書に場所を譲るために記述は削除されてしまったのだ。

M-(にプレフィックス引数を与えるとその個数分のsexpのカッコで括るようになっている。たとえば"*"がポイントを表すとして:

*foo -> C-u 1 M-( -> (foo)

EmacsWikiに、更に詳しい情報が記述されている。

u/PriorOutcome

🔗

Votes 10

magitでmasterブランチと機能ブランチを切り替えたいときがよくある。

(defun lw-magit-checkout-last (&optional start-point)
    (interactive)
    (magit-branch-checkout "-" start-point))
(transient-append-suffix 'magit-branch "w"
  '("-" "last branch" lw-magit-checkout-last))

こうしておけばcd -のように、前にいたブランチにC-x g b -で切り替えられるようになる。

u/sauntcartas

🔗

Votes 10

わたしはpcaseマクロが如何に役に立つかを忘れてしまいがちだ。特定のディレクトリから1つのjarファイルを見つけて処理を行うコマンドを最近記述した。最初は"古風"に実装した:

(let ((jars (directory-files some-dir t (rx ".jar" eos))))
  (if (= 1 (length jars))
      (do-something-with (car jars))
    (error "Didn't find exactly one jar file")))

pcaseを思い出したのはその後だ:

(pcase (directory-files some-dir t (rx ".jar" eos))
  (~(,jar) (do-something-with jar))
  (_ (error "Didn't find exactly one jar file")))

とても読みやすくなったよ!

u/11fdriver

🔗

Votes 10

何ページかに渡る関数のあるプログラムをときどき記述するが、そのときはfollow-modeを使用する。同じバッファーにウィンドウを2つオープンする。あたかもその間にテキストフローがあるような2冊の本のようにして横に並べて使うのだ。一度に閲覧できる行が2倍から3倍になる

これはそれまで使っていたコード概観マップを置き換えてしまった(いずれにせよわたしは端末からEmacsを使うのが好きなのでEmacsでなければ難しいのだが。

ファイル内を移動してもテキストの位置揃えは維持される。<mouse-5><mouse-4>xterm-mouse-modescroll-up/down-lineにバインドすれば使い勝手がよくなる。

勉強たメモとりをする場合には、結局Emacsウィンドウを垂直に積み上げたレイアウトに落ち着くこともよくある。winner-modewindow-configuration-to-registerも素晴らしいが、レイアウトをめちゃくちゃにせずにスクリーン上の実際の垂直状態を手早く取り戻したい場合には、follow-modeはとても直感的だし、同一バッファーにたいして複数ウィンドウを切り替えているだけなので使用も簡単だ。

u/b3n

🔗

Votes 10

EmacsのSkeletonは、特にabbrev-modeと組み合わせたときは、キラー機能の1つへと昇格する。以下は少し扱いやすくするために記述したマクロだ:

(defmacro snip (name &rest skeleton)
  (let* ((snip-name (symbol-name ~,name))
         (func-name (intern (concat "snip-" snip-name))))
    `(progn
       (define-skeleton ,func-name
         ,(concat snip-name " skeleton")
         ,@skeleton)
       (define-abbrev global-abbrev-table ,snip-name
         "" ',func-name))))

このマクロを用いた1番簡単な例を挙げよう:

(snip dd "" (format-time-string "%Y-%m-%d"))

(abbrev-modeが有効だとすると)これでバッファーにdd (ddSPC)をタイプすれば、これはカレント日付に置き換えられるだろう。

これは表面を引っ掻いたに過ぎないが、skeletonはとんでもなく強力なのだ。これらは使い始めることによって更に力を発揮して、あなたのEmacsの使い方を別次元に引き上げてくれる筈だ。

u/Bodertz

🔗

Votes 10

メーリングリストを読んで、/etc/fstab/etc/passwdといったファイルにたいして構文ハイライトを提供するgeneric-x.elを学んだところだ。Vimでは何もしなくてもこれがサポートされていて重宝したが、Emacsでも提供されていたこと、そしてデフォルトでは無効になっていることに驚いている。

有効にするには(require 'generic-x)だ。

u/WorldsEndless

🔗

Votes 10

イカした概念だと思う:
滅多に使わない手持ちのテンキーパッドがあれば、numsキー(テンキー)を何か役に立つものにバインドするのだ。結果として得られるのはNumLockを考慮する、すなわち通常の数字とは異なるキーコード、自由なキーをもつキーだ。たとえば(define-key map (kbd "<kp-1>") 'winum-select-window-1)とバインドして使ったりできるだろう。

u/Krautoni

🔗

Votes 10

自分が最近ペアプログラミングを行うことに気づいて、小さいヘルパーを作ってみた:

(defvar pair-programming--pair-programmer
  nil
  "カレントのペアプログラマー(名前 メール)")

(defun enable-pair-programming-mode ()
  "ペア相手用にペアプログラミングモードとプロンプトのビジュアルをセットする"
  (global-display-line-numbers-mode 1)
  (let ((pair-programmer (git-commit-read-ident nil)))
(setq pair-programming--pair-programmer pair-programmer)
(message (concat "Pair programming with " (car pair-programmer)))))

(defun disable-pair-programming-mode ()
  "ペアプロ用のビジュアルとセッティングを無効化"
  (setq pair-programming--pair-programmer nil)
  (global-display-line-numbers-mode -1)
  (message "PP mode disabled"))

(define-minor-mode pair-programming-mode ()
  "Pair Programmingモードの切り替え

ペアプログラマーにカレントのgitのコミット履歴の入力を求める
あなたがgit(magit)でコミットすると共同プログラマーとしてペアプログラマーが挿入される
更に追加で行番号も有効にする"
  :global t
  :lighter " PP"
  (if pair-programming-mode
  (enable-pair-programming-mode)
(disable-pair-programming-mode)))

(defun insert-pair-programmer-as-coauthor ()
  "カレントのgitコミットにペアプログラマーを挿入"
  (when (and pair-programming-mode git-commit-mode)
(pcase pair-programming--pair-programmer
  (`(,name ,email) (git-commit-insert-header "Co-authed-by" name email))
  (_ (error "No pair programmer found or wrong content")))))

(add-hook 'git-commit-setup-hook 'insert-pair-programmer-as-coauthor)

これはgitコミットにco-authored-byをセットアップして、行番号を有効にする。

u/Amonwilde

🔗

Votes 10

ほとんどの人にとってはすでに明白なことかもしれないが、少なくとも1人くらいは役に立つと思ってくれるだろう。Emacsの素晴らしい機能の1つ、dabbrev-expandについてだ(デフォルトではM-/にバインドされている)。

前の単語を"動的(dynamically)"に展開する。

先行するもっとも最近の単語をプレフィックスとするような単語を展開する。先行する単語に適した単語がなければポイント以降の単語が考慮される。それでも適切な単語が見つからなかったら、変数に指定された関数が許容するバッファーを調べるだろう。

このコマンドは詰まるところオムニ補完(omni-autocomplete)である。補完しようとしている用語は多分ここや別のバッファーで以前使用した単語という前提に基づいて、それらの異なる補完候補間を複数回巡回できるのだ。わたしの場合にはこの展開処理は言語のautocompleteに比べて70%ほど高速かつより決定論的だった。あなたがEmacsをプログラミング以外に使用する場合、特に文書の記述に用いているのなら、間違っていない正確な単語、特化した語彙を正しく記述する際に特に役に立つだろう。

u/[あぼーん]

🔗

Votes 10

モデレーターへの提案

  • その1
    古いredditでは機能しない3連のバッククォートやチルダで定義されたコードブロックを使っているスレッド用に、週間アナウンスにノートを配置することを検討してもらえないだろうか(コードブロックになっていないとユーザーのポストしたコードがほとんど読めないから)。

  • その2
    古いredditとの互換性を考慮して、バッククォートやチルダではなく4つのスペースでインデントするのだ(それとも古いredditを使っているのはわたしだけだったりする?
    :-) )

u/[あぼーん]🔗

Votes 10

Emacsパッケージのベスト2つがUndo-treeとKill-ringだ。これで人生を変えよう。

\** u/b3n
🔗
\*Votes* 10

1日のある時刻に応じて2つのテーマ(たとえばlightとdark)を切り替えたければ、以下のようにすれば簡単だ:

;; Light
(load-theme 'modus-operandi t t)
(run-at-time "05:00" (* 60 60 24)
             (lambda ()
               (enable-theme 'modus-operandi)))

;; Dark
(load-theme 'modus-vivendi t t)
(run-at-time "21:00" (* 60 60 24)
             (lambda () (enable-theme 'modus-vivendi)))

これはEmacs起動時に正しいテーマを選択して、時間になったら自動的にテーマを切り替えるスニペットだ。

u/konrad1977

🔗

Votes 10

use-package-compute-statistics t と(M-x)
use-package-reportについて完全に忘れていた。これのお陰で3秒ほどだった起動時間を1秒未満に最適化できたのだ。

u/cidra_

🔗

Votes 10

本日学んだこと:
CSSスタイリングをシンプルにオーバーライドするだけで、EmacsのGTKコンポーネントのスタイリングができること。これを行うためのイカしたパッケージとしてGitHubに)もあるが、以下の関数使ってGTKインスペクターを呼び出せば、何もパッケージを追加せず"リアルタイム"で簡単に微調整できることが判った。

(x-gtk-debug t)

わたしが本当に実現したかったのは、GNOMEを使ってEmacsフレームの下端エッジのコーナーの丸めだ。これを行うにはクライアント側のデコレーションでそのようにする必要がある。すべての場所border-radius属性を適用してみたが、、これはGTKの標準コンポーネントではないためメインパネルで動作しなかった。ツールバーを下端位置に配置して、それにborder-radiusを適用して実現できた。メインウィンドウとメインウィンドウ上にあるdecorationコンポーネント(フレームに影を付与する)にもborder-radiusスタイルを適用してみた。

img

decoration {
    border-radius:12px;
}
    
window{
    border-radius: 12px;
}
    
menubar{
/*
   理由は不明だがメニューバーにも
   border-radiusが適用されてしまう
   それへの対処
 */
    background-color: white;
}
    
toolbar {
    border-radius: 12px;
}

現時点ではフレーム背後のシャドーやコンテキストメニューは削除せずにヘッダバーを削除できないか試している 🤔

u/ImJustPassinBy

🔗

Votes 10

M-x make-frameがマウスカーソルがあるモニター上に新たにフレームを作成することに気づいた。複数モニターを使用している人たちなら、表示したいモニターにマウスを配置してM-x make-frame-on-monitorを実行すれば簡単にモニターを選択できるのである。

u/meain

🔗

Votes 10

ヘッダ(最初の10行"DO NOT
EDIT"が含まれていれば、バッファーにread-only-modeをセットする。生成されるファイルは、通常であれば手作業で編集したくないものもあるだろう。

(use-package emacs
  :config
  (defun meain/set-read-only-if-do-not-edit ()
"コンテンツに'DO NOT EDIT'が含まれていればバッファーを読み取り専用にセットする
最初の10だけに検索を絞ることによってヘッダだけをチェックしている"
(save-excursion
  (goto-char (point-min))
  (let ((content
         (buffer-substring (point)
                           (save-excursion (forward-line 10) (point)))))
    (when (and (not buffer-read-only)
               (string-match "DO NOT EDIT" content))
      (read-only-mode 1)
      (message "Buffer seems to be generated. Set to read-only mode.")))))
  (add-hook 'find-file-hook 'meain/set-read-only-if-do-not-edit))

u/regob

🔗

Votes 9

bashのコマンドラインでC-x C-eをタイプすればカレントのコマンド行をEmacsでオープンして編集できる(Emacsと関係ないかもしれないが、端末で作業するときには重宝している)

u/[あぼーん]

🔗

Votes 9

[あぼーん]

u/MotorMouth_

🔗

Votes 9

rg.el
(ripgrep用のEmacsインターフェイス)のユーザーにはpdf、docx、sqlite、jpg、mkvやmp4のサブタイトル等からの検索を可能にするためのripgrep用のラッパーとしてrga(ripgrep-all)が存在する。"rg.el"のコンフィグで(setq rg-executable (executable-find "rga")とすれば、複数のドキュメントタイプでの検索が可能になるようにrgの実行可能形式をセットできる。

u/[あぼーん]

🔗

Votes 9

最近Dimmerというパッケージを発見したが、今までこれを試していなかったことを信じられない。これはフォーカスのあるウィンドウが目を引くのに十分な程度、他のウィンドウを薄暗くするのだ。どの位薄暗くするか、除外するバッファー等はもちろんカスタマイズ可能だ。

わたしはこのように認知負荷を軽減してくれるものが好きだ。必要に迫られるまでは、お決まりのカーソルといった些細な手掛かりを探すことに、どれだけ時間を要したかは気が付かないものだ。

u/pt-guzzardo

🔗

Votes 9

(defun copy-source-for-reddit ()
  (interactive)
  (let ((contents (buffer-substring (point) (mark))))
    (with-temp-buffer
      (insert contents)
      (mark-whole-buffer)
      (indent-rigidly (point) (mark) 4 t)
      (mark-whole-buffer)
      (kill-ring-save 0 0 t))))

コードをredditのマークダウンにエクスポートするためのお手軽なスニペットだ。リージョン内の各行の先頭にスペースを4つして、元のバッファーは変更せずにブラウザに割り付けられるようにkillリングにコピーするのだ。

u/demosthenex

🔗

Votes 9

elisp lのコーディングを学ぶときに、M-x ielmはREPL使っている。知らなかった!

u/lesliesrussell

🔗

Votes 9

transientの移動用のマップだ。

移動を制御するtransientキーマップを定義して、このtransientマップをアクティブにするグローバルなキーバインディングをセットアップする。このtransientマップmy-movement-transient-mapには単語や文字単位での前後移動や上下の行に移動するためのさまざまな移動コマンドのためのバインディングが含まれている。このtransientマップをアクティブにするために定義したのがaactivate-my-movement-mapだ。これはC-fにグローバルにバインドされている。


これは`C-f`の後に指定したキーのいずれか(`f`、`b`、`c`、`l`、`n`、`p`)w押下することでそれらに応じた移動処理を行うようにセットアップして!ある。これらのキーのいずれかが押下されるまでtransientマップがアクティブであることを保証するために、`set-transient-map`はの2つ目の引数を`t`にして呼び出している。

これはEmacsにおいて移動用にモーダル風なインターフェイスを作成してカスタマイズする正式な方法だ。あなたの好みに応じて編集環境を設えるようにEmacs
Lispのスキルを活用できるだろう。固有の移動や実装したい追加機能があれば、遠慮なく尋ねて欲しい!

スレッドにコードを置き去りにしたくなかったので、gistに投稿した。

u/[あぼーん]

🔗

Votes 9

これを使えばデバッグバッファーのスタック出力が格段に読みやすくなる:

(setopt debugger-stack-frame-as-list t)

u/Netherus

🔗

Votes 9

M-uで次の単語を大文字、M-lで小文字にできることに最近気がついた。特に目新しい訳ではないかもしれないが、わたしには便利。

u/frosch03

🔗

Votes 9

非常に役に立つのだが、すぐに忘れてしまう:

1つのフレームでバッファーを2つオープンしていて一方は数行だけ、もう一方はたくさんの行が含まれているようなときは、C-x -を使えばバッファーを縮小できるのだ。

再び釣り合いを取りたければC-x +だ。

u/PriorOutcome

🔗

Votes 9

capitalize-wordより汎用的に置き換えるために、ポイント位置にある単語を"柔軟(flexing)"にするケースを少しづつ蓄積している:

;; どこかのwikiから拝借
(defun increment-number-at-point ()
  "ポイント位置の数値を加算"
  (interactive)
  (skip-chars-backward "0-9")
  (or (looking-at "[0-9]+")
      (error "No number at point"))
  (replace-match (number-to-string (1+ (string-to-number (match-string 0))))))
    
(defun lw-flex ()
  "ポイント位置のスマートなflexingを行う
    
たとえば次の単語のキャピタライズやキャピタライズを解除するために
ポイント位置の数を加算"
  (interactive)
  (let ((case-fold-search nil))
    (call-interactively
     (cond ((looking-at "[0-9]+") #'increment-number-at-point)
           ((looking-at "[[:lower:]]") #'capitalize-word)
           ((looking-at "==") (delete-char 1) (insert "!") (forward-char 2))
           ((looking-at "!=") (delete-char 1) (insert "=") (forward-char 2))
           ((looking-at "+") (delete-char 1) (insert "-") (forward-char 1))
           ((looking-at "-") (delete-char 1) (insert "+") (forward-char 1))
           ((looking-at "<=") (delete-char 2) (insert ">=") (forward-char 2))
           ((looking-at ">=") (delete-char 2) (insert "<=") (forward-char 2))
           ((looking-at "<") (delete-char 1) (insert ">") (forward-char 1))
           ((looking-at ">") (delete-char 1) (insert "<") (forward-char 1))
           (t #'downcase-word)))))

わたしはM-cにバインドしている。

u/pathemata

🔗

Votes 9

複数の辞書用にaspellをセットアップした人はいるだろうか?

--extra-dictオプションを試みると、Expected language "en" but got "de"というエラーになる(訳注:
エラーは"言語に英語を期待したけどドイツ語だった"という意味):

u/gusbrs

🔗

Votes 9

数週間前だっただろうか、u/paretoOptimalDevから、switch-to-bufferのかわりにnext-bufferprevious-bufferを使うという興味深い投稿があった。投稿が気に入ったので、後で処理できるようにキャプチャしておいたが、やっと着手できるようになった。

next-bufferprevious-bufferを使うのは良いとして、デフォルトのバインディングにはほとんどの人が不満をもっているだろう。

Emacs 28ではrepeat-modeか含められて、Emacs
29ではrepeat-modenext-bufferprevious-bufferが追加されたのフリ注目に値する。もしEmacs
29を使っているようならrepeat-modeを有効にするだけで改善された挙動不審わ得ることができるだろう。最初はC-x <right>、その後は矢印キーだけで前後のバッファーに移動できるのだ。

まだEmacs 28を使っているなら:

(defvar buffer-navigation-repeat-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "<right>") 'next-buffer)
    (define-key map (kbd "<left>") 'previous-buffer)
    map)
  "`next-buffer'と`previous-buffer'をrepeatするキーマップ
`repeat-mode'で使用する")
(put 'next-buffer 'repeat-map 'buffer-navigation-repeat-map)
(put 'previous-buffer 'repeat-map 'buffer-navigation-repeat-map)

u/PriorOutcome

🔗
Votes 9

(たとえばデバッグ用に)Projectileのデフォルトのモードラインインジケーターをオーバーライドして、かわりにProjectileプロジェクトのタイプをバッファーに表示できれば非常に役に立つことが判った。これはhttps://elpa.gnu.org/packages/delight.htmlと一緒にuse-packageを使っていればとても簡単に実現できるのだ:

(use-package projectile
  :delight '(:eval (format " P[%s]" (projectile-project-type)))
  :config
  (setq foo "bar"))

u/hairlesscaveman

🔗

Votes 9

質問:
一般的に3つ目の垂直パネルで作業することが多い。左にコード、真ん中がテスト関連のファイル、右はテスト出力かmagitというレイアウトが好みだ。しかしこのレイアウトを維持するのは少々厄介だ。ときどきmagitが1つ目のパネルやわたしが作業している真ん中のパネルにオープンしたり、どこかにdeadgrepがオープンしたり…
そう、いささか支離滅裂でランダムすぎるように感じられる。

パネル1か2ではファイルをオープンしてmagit、test-output、deadgrep等は常にパネル3でオープンするようにできないだろうか?
"shackle"を試したが駄目だった。コンフィグに関係なく何もかもスクリーン下部の水平パネルにオープンするように見える。

どんなヒントでも歓迎する!

u/PriorOutcome

🔗

Votes 9

このスレッドの過去のコメント(何か取りこぼしているかもしれないが、いずれ解決したいと思っている)をいくつか解析、体裁を整えてみた:
https://github.com/LaurenceWarne/reddit-emacs-tips-n-tricks/blob/master/out.md

今日を少しだけ先に伸ばしたいのなら…

u/[あぼーん]

🔗

Votes 9

水平スクロールが左にスクロールし過ぎないようにする。

ラップトップでEmacsを使っていて、タッチパッドでスクロールする機会が多い。行の折り返しもコードを見る際に間違えやすいので使っていないので、ウィンドウ幅を超える行にもときどき遭遇する。どちらも長過ぎる名前、あるいはウィンドウのカレント構成が狭すぎるのが原因だ。

テキストを横にスクロールする際に左にスクロールし過ぎるときがあるのが問題だ。たとえばウィンドウ幅を超えるテキストがあるウィンドウで:

|Short line             |
|Some really long line o|
|Another short line     |

以下を超えるようなスクロールはして欲しくない:

|line                   |
|eally long line of text|
|r short line           |

しかしEmacsはわたしが望む以上にスクロールできてしまうのだ:

|                       |
|t                      |
|                       |

そんなにスクロールしても見るべきものがないので、わたしにとっては意味のないスクロールだ。非常に長い行を記述する際にはスクロールがトリガーされないようにテキスト追加用に別バッファーを使えば便利かもしれないが、わたしの好みに合わない。したがって以下のような述語関数を記述した:

(defun truncated-lines-p ()
  "`window-width' + `window-hscroll'より長い行があれば非nil

ウィンドウの右ボーダーを超える行があればtをリターンする
もっとも長い行を超えてスクロールさせないために用いる
`so-long-detected-long-line-p'を元にした"
  (save-excursion
    (goto-char (point-min))
    (let* ((window-width
            ;; `text-scale-mode'のフォント幅をを考慮
            ;; `window-width'より正確に幅を算出する
            (/ (window-body-width nil t) (window-font-width)))
           (hscroll-offset
            ;; `window-hscroll'は`text-scale-mode'を考慮しない列をリターンする
            ;; したがって正しい`window-hscroll'を再計算するには、
            ;;   スケールされていない値を乗じてスケール幅で除して
            ;;   上限に丸める必要がある
            ;; スケールされていない幅の値を取得する方法がないので、
            ;;   `window-divider'フェイスのように`text-scale-mode'で
            ;;   スケーリングされないフェイス幅を取得する
            (ceiling (/ (* (window-hscroll) (window-font-width nil 'window-divider))
                        (float (window-font-width)))))
           (line-number-width
            ;; 行番号の幅を担保
            (if (bound-and-true-p display-line-numbers-mode)
                (- display-line-numbers-width)
              0))
           ;; 計算結果が不正解な場合に備えてスペース2つ余分に減じる
           (threshold (+ window-width hscroll-offset line-number-width -2)))
      (catch 'excessive
        (while (not (eobp))
          (let ((start (point)))
            (save-restriction
              (narrow-to-region start (min (+ start 1 threshold)
                                           (point-max)))
              (forward-line 1))
            (unless (or (bolp)
                        (and (eobp) (<= (- (point) start)
                                        threshold)))
              (throw 'excessive t))))))))

この関数はウィンドウと行の幅を計算して、スクリーン的にウィンドウ幅を超える長さの行がバッファーにあるかチェックする。スクリーン的というのはテキストを左にスクロールした場合にウィンドウの右ボーダーを超える行が存在しなくなればnilをリターンするので図示した動作が実現できるという意味で用いている。それからscroll-left:aroundにこの関数をadviceしたら良好に機能した:

(define-advice scroll-left (:around (foo &optional arg set-minimum))
  (when (and truncate-lines
             (not (memq major-mode '(vterm-mode term-mode)))
             (truncated-lines-p))
    (funcall foo arg set-minimum)))

行の幅が以前と異なるのでtext-scale-adjustはあまり正確ではないし、左にどれだけスクロールされているかをリターンする関数は、依然としてスケーリングされていない値をリターンする。わたしの想いは関数のコメントを読めば判るだろう。もっと正確にする方法はないものだろうか?

u/blankspruce

🔗

Votes 9

magitのdiffにたいしてwdiredやwgrepと同等に機能するようなパッケージはないだろうか?

わたしが思い描く使い方としては:

  1. プルリク用コミット準備でのレビュー中に複数の間違いがコミットの複数ファイルに存在することを指摘、通常はその間違いをgrepして影響するファイルだけwgrepで編集する(そのコミットに含まれていないファイルにある同様な問題については訂正しないという具体的な理由がある)
  2. C++では個別に宣言と定義したい場合があり、コミットで定義をいくつか"*.cpp"に移動し忘れたときは、通常だとfoobar.hppから必要な部分をkillしてfoobar.cppにyankする
訳者追訳

divinedominionより
あるあるだな! Emacsのdiffモード用のインプレース編集って無いものか?
通常はこのようなタスクにEmacsを使ってないので利用できるdiffモードはどれも経験無いけれど、それほど魅力的なら是非使ってみたいもんだ :)
ediffは別個に'制御バッファー(control buffer)'が必要だが、これはあまりよろしくない。
オプションとしては[emacs-vdiff](https://github.com/justbur/emacs-vdiff)か?
そうなると次はmagitのdiffをそれに変更可能かどうかだな。


TeMPOraL_PLより

> ediffは別個に'制御バッファー'が必要だが、これはあまりよろしくない。
遂に意を決してediffマニュアル(M-x
infoで閲覧できるEmacs同梱のInfoページだ)を最初から最後までのうち半分程度読破した。わたしにとってのediffエクスペリエンスを向上させる2点について:

その1: M-x ediff-toggle-multiframe
"control
buffer"を別フレームにフローティングさせるか、diff閲覧中のフレームに埋め込むかを切り替える。ediffが1回目の呼び出しを事実上無視するというバグがあるようなので2、3回呼び出す必要があるかもしれない。セッションを跨いで自分好み設定を引き継ぐ方法はありそうだが、そこまでマニュアルを読んでいない。

その2
コントロールバッファーで"|"を押下して分割の垂直水平を切り替える。一発で自分が望んだdiffインターフェイスに変更できる。

更に制御バッファーで"?"を押下すると1行に畳めるのでそれほどスペースは使わない。diffしながらdiffしているファイルを実際に編集できる点が制御バッファーの強味らしい。マニュアルによればこれは実のところ想定された使い方のようだ。編集によりediffが混乱するような場合には、制御バッファーで"!"を押下してリフレッシュできる。

"セッションマネージャー(session
manager)"もある。ediffセッションを閉じる(q)かわりにサスペンド(z)できるのだ。通常の作業を終えた後にeregistry(またはediff-show-registry)を呼び出せば、とっておいたdiffに戻れる。同様にして任意個数のediffセッションのサスペンドと再開ができ、マニュアルによればこれは実際にユーザーがediffで使っている方法だとのこと(フォルダのdiffをとるようなコンテキストではファイルごとにセッションがもてるので意味があるのだろう)。

Magit自体についてはediffと統合済みらしい(Magitのmainインターフェイスの"e"と"E"を参照)。Magitが行単位ではなく文字単位で完全に任意のhunkのステージングを行う手段として、ediffを使用していると何かで読んだ記憶がある。

まだ試してはいないが。

u/[あぼーん]

🔗

Votes 9

Topsyモードモードは要チェック。視覚的にページ範囲外にある最初の関数名を表示するヘッダをバッファー上端に作成するモードだ。バッファー内での位置を把握するための視覚的キューが追加されるので、コードをスクロールして閲覧するのだ簡単になる。知りたいと思ってもみなかった機能の1つだと思う。セットアップに要するのは15秒ほど。

u/oantolin

🔗

Votes 9

Imenuには強い中毒性があるが、一部のメジャーモードではサポートされていないのが残念だ。幸いなのメジャーモードに新たにimenuサポートを提供させるregexpは簡単に作成できる点だ。たとえば最近、Customizeバッファーにimenuサポートがないのに気づいて記述したのが以下:

(defun configure-imenu-Custom ()
  (setq imenu-generic-expression
        '(("Faces" "^\\(?:Show\\|Hide\\) \\(.*\\) face: \\[sample\\]" 1)
          ("Variables" "^\\(?:Show Value\\|Hide\\) \\([^:\n]*\\)" 1))))

(add-hook 'Custom-mode-hook #'configure-imenu-Custom)

勘所としてはcustomizeモードでは"Show"、"Hide"、"Show
Value"という単語のかわりに小さな三角形が表示される点への対処だ。バッファーの実際のテキストはC-u C-x =で調べられる(ポイント位置のすべてのオーバーレイを表示する)。

u/globalcandyamnesia

🔗

Votes 9

選択を格段するためにM-@ (次の単語までマーク)、C-M-@
(次のsexpまでマーク)のようなマークセッティング用のコマンドを使っているのなら、C-x C-xでポイントとマークを入れ替えられる。選択は右ではなく左に拡張されるだろう。

たとえばセンテンスの途中で何度かM-@を押下して何個か先の単語を選択してからC-xxを押下、そしてM-@を何度か押下すれば選択より前の単語を選択できる。

u/andrmuel

🔗

Votes 9

今ではあまり使っていないが、"わたしがEmacsに恋した瞬間"の1つなので共有したい。

会議のメモにorg-modeのジャーナルを使っていた。会議後にその会議を(ODTで)PDFにエクスポートして、出席者にメールしていたのだ。

しばらくしてから自動的に以下を行うようにorg-exportを拡張してショートカット化した(C-e C-s o M)

ODTでPDFにエクスポート

  • ODT_STYLES_FILEヘッダで会社の正式なデザインとロゴを使用する

カレント日付を含む名前にファイルをリネームする

thunderbirdをオープンして、以下のメッセージを開始する

  • すべてエクスポートした場合にはドキュメントタイトル、一部をエクスポートした場合にはそのヘッダから取得した件名
  • 事前に用意したテキスト
  • アタッチ済みのエクスポートしたPDF
;;
;; エクスポートとメール送信
;;
(defun org-foo-export-to-foo-and-sendto-mail (org-export-function &optional async subtreep visible-only ext-plist)
  (interactive)
  (when (or (string-equal (file-name-extension (buffer-file-name)) "gpg")
            (string-equal (file-name-extension (buffer-file-name)) "asc"))
    (unless (yes-or-no-p "Really export GPG encrypted file and send via mail? ")
      (throw 'abort-export-mail-gpg "export aborted by user")))
  (unless subtreep
    (unless (yes-or-no-p "Really export everything and send via mail? ")
      (throw 'abort-export-mail-everything "export aborted by user")))
  (let* ((title (if subtreep
                    ;; subtreeならサブツリーのヘッダをタイトルに
                    (nth 4 (org-heading-components))
                    ;; ドキュメント全体ならドキュメントタイトルを使う
                    (org-element-map
                        (org-element-parse-buffer)
                        'keyword
                      (lambda (e)
                        (when (string= "TITLE" (org-element-property :key e))
                          (org-element-property :value e)))
                      nil
                      t)))
         (file (file-name-nondirectory (funcall org-export-function async subtreep visible-only ext-plist))) ; note: odt export includes directory in output file name, html export includes no directory
         (newfile (format "%s_%s" (format-time-string "%Y%m%d") file))
         (directory (file-name-directory (buffer-file-name))))
    (rename-file (concat directory file) (concat directory newfile) 1)
    (my/thunderbird-compose-mail
     ""
     (format "Notes: %s" title)
     "Please find attached my notes ...\n\nBest regards, Andreas"
     (format "file://%s%s"
             directory newfile))))
    
(defun org-odt-export-to-odt-and-sendto-mail (&optional async subtreep visible-only ext-plist)
  (interactive)
  (org-foo-export-to-foo-and-sendto-mail 'org-odt-export-to-odt async subtreep visible-only ext-plist))
    
(defun org-odt-export-to-pdf-and-sendto-mail (&optional async subtreep visible-only ext-plist)
  (interactive)
  (let ((org-odt-preferred-output-format "pdf"))
    (org-odt-export-to-odt-and-sendto-mail async subtreep visible-only ext-plist)))
    
(defun org-html-export-to-html-and-sendto-mail (&optional async subtreep visible-only ext-plist)
  (interactive)
  (org-foo-export-to-foo-and-sendto-mail 'org-html-export-to-html async subtreep visible-only ext-plist))
    
(eval-after-load 'org
 '(progn
    (org-export-define-derived-backend 'odt-mail 'odt
      :menu-entry
      '(?o "Export to ODT"
           ((?m "As ODT file and send mail" org-odt-export-to-odt-and-sendto-mail)
            (?M "As PDF file and send mail" org-odt-export-to-pdf-and-sendto-mail))))
    
    (org-export-define-derived-backend 'html-mail 'html
      :menu-entry
      '(?h "Export to HTML"
           ((?m "As HTML file and send mail" org-html-export-to-html-and-sendto-mail))))))
           
(defun my/thunderbird-compose-mail (&optional recipient subject body attachment)
  (interactive)
  (call-process "thunderbird" nil 0 nil "-compose" (format "to='%s',subject='%s',body='%s',attachment='%s'" recipient subject body attachment)))

u/[あぼーん]

🔗

Votes 9

"org-variable-pitch.el"のユーザーならvalignを検討してみてはどうだろうか。これならイメージ(LaTeXプレビュー等)やリンクがあっても、テーブルを見栄え良く調節してくれる。OVPのコンテキストにおいて特に着目したいのがorg-variable-pitch-fixed-facesorg-linkする必要がないという点だろう。これは表に適合するようにvalign-modeが可変ピッチのリンクを処理してくれるからだ。

OVPは使っていなくてもテーブル内のLaTeX要素やイメージに限っても、依然として役に立つパッケージだ。

小さくて素晴らしいパッケージにたいして作者に感謝だ。

u/Rotatop

🔗

Votes 9

書き終えた!

Emacsを使って半年、C-c
C-Oやhydraやalt-enterを使わずにSHIFT+矢印キーで直接ivyでサイドバッファーをオープンできるようになった。

;; (setq windmove-create-window t)え新たなウィンドウを自動作成
;;
https://people.gnome.org/~federico/blog/bringing-my-emacs-from-the-past.htmlに感謝
;; "C-x o"のかわりにSHIFT+矢印キーでいつでもウィンドウ切り替えが可能
    
;; 美しくないハック:
;; SHIFT+矢印キー(上下左右)で新規分割したウィンドウに選択範囲を表示させたいので
(defun tim/ivy-down-other ()
  (interactive)
  (ivy-exit-with-action #'tim/ivy-down-exit))
    
(defun tim/ivy-left-other ()
  (interactive)
  (ivy-exit-with-action #'tim/ivy-left-exit))
    
(defun tim/ivy-right-other ()
  (interactive)
  (ivy-exit-with-action #'tim/ivy-right-exit))
    
(defun tim/ivy-down-exit (ivy-body)
  (split-window-below)
  (other-window 1)
  (tim/reuse-open-goto-line ivy-body))
    
(defun tim/ivy-left-exit (ivy-body)
  (split-window-right)
  (tim/reuse-open-goto-line ivy-body))
    
(defun tim/ivy-right-exit (ivy-body)
  (split-window-right)
  (other-window 1)
  (tim/reuse-open-goto-line ivy-body))
    
    
;; https://github.com/abo-abo/swiper/blob/master/doc/ivy.org#actions、および
;; https://www.reddit.com/r/emacs/comments/efg362/ivy_open_selection_vertically_or_horizontally/に感謝
(defun tim/reuse-open-goto-line (ivy-body)
  (message "reuse-open-goto-line ivy-body: %s" ivy-body)
  (let* ((tim/list (split-string ivy-body ":"))
         (file (car tim/list))
         (tim/number (car (cdr tim/list))))
    
    (condition-case err
        (counsel-projectile-find-file-action file)
      (void-function ; <- that s the error handler name
       (message "open fail with projectile, try find-file. Error was: %s" err)
       (find-file file)))
    ;; https://stackoverflow.com/questions/3139970/open-a-file-at-line-with-filenameline-syntaxに感謝
    (when tim/number
      ;; 対話的に使う用のgoto-line
      (goto-char (point-min))
      (forward-line (1- (string-to-number tim/number))))))
  ;; (ivy-resume)) ;奇妙なことにivy-resumeを使うと'ENTER'やivy-doneの動作が変更される
  ;; 回避策としてタイマーを試みる ;だめぽ
  ;; (run-with-timer 0.1 nil 'ivy-resume))
    
(use-package! ivy
  :bind (:map ivy-minibuffer-map
         ("C-p" . ivy-previous-history-element)
         ("<S-down>" . tim/ivy-down-other)
         ;; no up to avoid changing buffer problems
         ("<S-left>" . tim/ivy-left-other)
         ("<S-right>" . tim/ivy-right-other))

やはりEmacsはいい

u/rhmatthijs

🔗

Votes 9

Mac: システム規模でlight/darkモードが利用可能かをEmacsで検出する。

lightとdarkの2つのテーマがある場合に、lightモードが有効になるまではデフォルトでdarkモードにするための"init.el":

;; Mac用
;; ファイル"~/bin/get_dark.osascript"が存在すれば"false"を出力してlightモード
;; それ以外の場合にはdarkモードをアクティブにする
(cond ((and (file-exists-p "~/bin/get_dark.osascript")
            (string> (shell-command-to-string "command -v osascript") "")
            (equal "false\n"
                   (shell-command-to-string "osascript ~/bin/get_dark.osascript")))
       (mcj/theme-set-light))
      (t (mcj/theme-set-dark)))

(mcj/theme-set-lightmcj/theme-set-lightはそれぞれlightあるいはdarkのテーマを有効にする関数)

~/bin/get_dark.osascriptの中身:

tell application "System Events"
	tell appearance preferences
		get dark mode
	end tell
end tell

u/attento_redaz

🔗

Votes 9

仕事用にzotracitar、Org-citeエコシステムの一部を合わせて基本的にはorg-bibtexに似ているが、bibtexのかわりに適切なプロパティを付与したヘッダでbibtexエントリーを表現する、"org-biblatex参考文献リスト(org-biblatex
bibliographies)"と協調動作する実験的ではあるが非常に快適な環境にハッキングした。zotraを使用してURLに応じたbibtexエントリーを取得して、それに対応するOrgヘッダにはプロパティとしてbibtexフィールドを付与、ドキュメントを保存すればすぐにCiterで利用可能なエントリーにする関数はある。これらのエントリーにたいする引用はどこでも使用できる。たとえ同じドキュメント内であっても、適切な#+bibliography: my-org-biblatex-file.org宣言があれば引用可能だ。引用のエクスポートはCSLエクスポーターでも機能する。biblatexの正しいbibliography(参考文献)ファイルへの変換等は何も必要としない(ただしbiblatexベースにしたければ簡単にエクスポートできる)。bibliographyはOrgドキュメントなので、エントリーにたいするタグ付け、アジェンダコマンド、columnビュー等は簡単に行うことができる。既存の材料と数行のEmacs
Lispによってどれだけ多くのことが達成可能なのか恐ろしくなるぐらいだ。

u/b3n

🔗

Votes 9

eshellバッファーが何個かあれば、生活品質を多少向上できる。

(defun eshell-buffer-name ()
  (rename-buffer (concat "*eshell*<" (eshell/pwd) ">") t))
    
(add-hook 'eshell-directory-change-hook #'eshell-buffer-name)
(add-hook 'eshell-prompt-load-hook #'eshell-buffer-name)

u/[あぼーん]

🔗

Votes 9

Meta+クリック+ドラッグで矩形選択(Rectangular Selection)を作成する

Metaキーを押したままクリックしてドラッグすれば、デフォルトのEmacsでは"セカンダリー選択(secondary
selection)"と呼ばれる興味深く非常に役に立つものが得られる訳だが、それに関する小技ではない。(少なくともMacの)ほとんどのエディターでは、矩形選択の作成にoption+クリック+ドラッグが用いられている。もちろんリマップするだけでEmacsでもサポートできる。

(global-set-key [M-down-mouse-1] #'mouse-drag-region-rectangle)
(global-set-key [M-drag-mouse-1] #'ignore)
(global-set-key [M-mouse-1]      #'mouse-set-point)

矩形選択はコマンドrectangle-mark-modeでも作成できる。

とても簡単に編集できるようにreplace-rectangleを何か便利なキーにバインドすること。

u/zackallison

🔗

Votes 9

emacsclientスレに投稿済みではあるが、ここにも投稿する価値はあるだろう:

emacsclient/serverシステムは素晴らしい。リモートに接続する際にTCPをlistenしてポートフォワードさせれば別次元のパワーを付加できる。

Emacs内部では端末にemacs-vtermを使っているので、たくさんのコマンドにたいするキーをリマップしてある。manemacsclient ... man ..といった具合だ。これは"別のバッファー"でmanページをオープンするので流れが中断させられることもない。プロンプトが表示されているときのmanページのナビゲーションには"scroll-other-window"を用いる。magitdired等他のコマンドもemacsclientの等価物にマッピングしてある。

emacsクライアント用のラッパースクリプトを記述したが、キーストローク節約のためにeと読んでいる。

完全なe-emacs.shのレポはココ

このスクリプトはわたしたちが期待するような標準的な処理を行い、起動していなければEmacsを起動して、ファイルを新たなバッファー/ウィンドウ/端末でオープン、終了まで待機するかシェルに戻って継続するかはオプションで選択可能だ。

それから自分で便利だと思った関数をいくつか追加、それからfind . -name foo\* | eのようにコマンドの出力結果をEmacsバッファーに流し込むためのpipeを開始するのだ。その後はe [file] | rot13のように非常に強力な暗号化を行うために自然とバッファーからpipeに流し込むということになる(訳注:
"非常に強力な暗号化を行う云々"はジョークです)。もちろんpipeからバッファー、そしてバッファーの外部への処理は、find . -name incriminating-evidence\* | e | xargs rmと同じように機能するので、それらを受け渡す前に結果の検証や微調整を行うことができる。ひょっとしてエロ関連倉庫に証拠でも残しておきたいのかもしれない。

他に優れた機能としては、テンプレートを任意に使用できる点だ。たとえばHTTPリクエストを編集してサーバーに送信するような場合には、e -t header_template.txt | nc www.example.com 80のようにすればよい。編集用にtempにテンプレートファイルがコピーされる。

貧者のブログシステムはe -t header_template.html body_template.html footer.html > new_page.htmlだ。

例やダウンロードについてはレポジトリを参照して欲しい。リモートマシンで動作させるためのメモはあまり明確とは言えない。あなたの人生を容易にするような提案や機能があれば是非教えて欲しい。

完全なe-emacs.shのレポはココ

実際のところこれはあなたの小技を何か投稿してもらいたくて投稿したのだが、とりとめない投稿になってしまった。 これで終わりだ。

あなたは知らないかもしれないが、わたしは実はEmacsとEmacsのクライアントサーバーモデルが本当に好きなのだ。

u/emacsomancer

🔗

Votes 9

共同執筆用に事前定義されているEmacs(文芸的かつ自己生成を行うinit):

https://gitlab.com/emacsomancer/collaborative-writing-environment-emacs

大量のパッケージからなる巨大なコンフィグではないがバージョンコントロール(magit)と協調する記述(org-mode、fountain)に焦点を置いている。

編集しているファイル箇所を示すために、各人に違うカラーが割り当てられる。スクリーンショットだ(EmacsでCory Doctorow氏がFor
the Winを共同執筆するような世界線より:)

https://imgur.com/a/zvfLpdH

u/ImJustPassinBy

🔗

Votes 9

手っ取り早く計算したいときはときどきあるがM-x calcに悪戦苦闘するのは嫌な人は、M-x quick-calcを試してみてはどうだろう。2*3.4+5のように式を入力すれば、結果が表示されてクリップボードにもコピーされる。

u/druuuun

🔗

Votes 9

今日、shift-select-mode'permanentにセットしたら世界が一変した。リージョンの拡大にはexpregを使うのが好みだが、一度リージョンを選択してから、SHIFT修飾した移動キー(C-S-fC-S-n等)でリージョンを変更するとリージョンが非アクティブになってしまうのを常々悩んでいた。shift-select-mode'permanentをセットすることで、SHIFT修飾されていないコマンドで作成されたかどうかに関係なく、アクティブなリージョンを変更できるようになった。

u/fv__

🔗

Votes 8

transientのポップアップでC-xを押下すると、選択したオプションを保存するメニューが表示される。これはmagitでpush(P
p)する際のデフォルトとして'force-with-lease選択させるように使うことができる。

u/meedstrom

🔗

Votes 8

Elispのリストのインデントが修整されてから2年以上経った(https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21922)。しかしリストが以下のようにインデントされてしまう問題を訂正するために、多くの人たちがinitファイルのhackを使っているのではないだろうか:

'(:foo bar
       :baz zab
       :rab oof)

しかし開きカッコ'(の後にスペースを1つ追加するだけで修整できるようになった。これは新しい規約だ。

'( :foo bar
   :baz zab
   :rab oof)

u/JDRiverRun

🔗

Votes 8

何人かの人たちからrepeat-modeがアクティブならカーソルカラーを変更する要望があった(コマンドのリピート中など)。いい改善だと思う。詳細についてはgistの投稿を参照して欲しい。

u/AdjointFunctor

🔗

Votes 8

最近になって矩形(rectangle)用のモードを再発見した。インデントを大量に削除する際には非常に役に立つ。C-x SPCの後にリージョンをマークするだけだ。https://emacsredux.com/blog/2014/01/01/a-peek-at-emacs-24-dot-4-rectangular-selection/

u/vjgoh

🔗

Votes 8

ディレクトリー階層途中でeglotがそこをプロジェクトのルートだと勘違いしてclangd用のインスタンスを個別に何個も立ち上げる問題に悩んでいる(合計で10個以上のときさえある)。プロジェクトの発見をEmacsビルトインのprojectに一任しているせいに違いないと思っている。この時点でprojectは使えないしprojectileに比べてドキュメントも貧弱なので、lsp-modeに切り替えた。

しかしlsp-modeが解析し失敗するので、結局eglotに戻らざるを得なかった。

手短に言うと、projectの自動検出にプロジェクトの実際のルートを指定する方法があった。これでeglotの動作は文句なし、clangdのインスタンスが何個も立ち上げるらず、すべてが快適に動作する。

(setq project-vc-extra-root-markers
      '(".project.el" ".projectile" ".dir-locals.el"))

u/AP145

🔗

Votes 8

多くの人たちがデフォルトのEmacsキーバインディングが如何に彼らの小指を痛めつけるかを主張していることを常々不思議に思っていたのだが、わたしはタッチタイピングしないのでデフォルトのキーバインディングならどれにアクセスしても無理に指を伸ばす必要がないからだということに気づいた。わたしのへっぽこタイピングが反復運動過多損傷から守ってくれていたとは皮肉なことだ。

u/BunnyLushington

🔗

Votes 8

今週始めにJWT(JSON Web
Token)
でデバッグ、リージョンからヘルプバッファーにデコードする関数をでっち上げた。

(defun ii/decode-jwt (start end &optional jwt)
  "リージョンのJWTをデコードしてヘルプバッファーにプリント"
  (interactive "r")
  (let* ((tok (if jwt jwt
            (buffer-substring start end)))
     (data (s-split "\\." tok))
     (header (car data))
     (claims (cadr data)))
(with-temp-buffer
  (insert (format "%s\n\n%s"
                  (base64-decode-string header t)
                  (base64-decode-string claims t)))
  (json-pretty-print-buffer)
  (with-output-to-temp-buffer "*JWT*"
    (princ (buffer-string)))))
  t)

こうゆうときに便利なwith-output-to-temp-bufferうぃ忘れていた。最後のtは単に無意味に大きなエコーエリアメッセージを抑止するためだけに追加した。

(JWTは検証も確認もされていなかったことは明確にしておくべきだろう。これは信頼できないJWTのデバッグだけを意図したコードだ。)

u/w0ntfix

🔗

Votes 8

org-elementsのキャッシュを切ったら入力の応答が高速化した(プロファイリングでは):

(setq org-element-use-cache nil)


(少なくともorg 9.6.1では)キャッシュの更新後に、(何回も)org-self-insert-commandを呼び出していたようだ。

u/SlowValue

🔗

Votes 8

わたしには似たような関数をいくつか<f5>キー(すべて修飾キーとの組み合わせだ)ににバインドしておいて、それらの組み合わせの意味を忘れてしまう傾向があるらしい。

それでキー一覧を表示する小さな関数を作った:

(defun my-generate-keybind-doc-on-keys (&rest keys)
  "あるキーバインディング(kbd形式)にたいするヘルプを生成"
  (substring
   (apply #'concat
          (mapcar #'(lambda (key)
                      (let* ((fun (key-binding (kbd key)))
                             (fun-name (symbol-name fun))
                             (doc (documentation fun 'raw))
                             (oneline (substring doc 0 (string-match "\n" doc))))
                        (put-text-property 0 (length key) 'face 'font-lock-keyword-face key)
                        (put-text-property 0 (length fun-name) 'face 'font-lock-function-name-face fun-name)
                        (put-text-property 0 (length oneline) 'face 'font-lock-doc-face oneline)
                        (format "%10s : %-30s → %s\n" key fun-name oneline)))
                  keys))
   0 -1))

このヘルプをエコーバッファーに表示するためには、キーにバインド可能なコマンドを定義する必要がある:

(defun my-show-help-on-some-keys ()
  "キー3つのヘルプ生成デモ"
  (interactive)
  (message (my-generate-keybind-doc-on-keys "C-s"
                                            "<f1> k"
                                            "C-c !")))

それからコマンドmy-show-help-on-some-keysを呼び出せば、エコーバッファーに以下のメッセージが表示される筈だ:

   C-s : isearch-forward                → 前方にインクリメンタル検索
<f1> k : helpful-key                    → KEY-SEQUENCEにバインドされているインタラクティブなコマンドを表示
 C-c ! : shell-here                     → デフォルトディレクトリーから相対的にシェルをオープンする


注: which-keyの存在は知っているがそのレベルの知識はもっているので、もうwhich-keyは必要ないのだ。

u/Nondv

🔗

Votes 8

これを聞くのが初めてではない人もいるだろうが、C-c <any letter>は規約によりユーザー用に予約済みであることをつい最近になって気づいた。わたしは何かをクラッシュさせてしまわないように、自分用のバインディングを定義するかわりにM-xを使いがちだった。これで自分が使っているコマンドのほとんどはバインドできるようになった。

上記を念頭に置いた上で、今度はバインディングを忘れてしまうwhich-keyパッケージを使っていたので"define-my-keybinding
letter fn"のような関数を記述した。これはアルファベットletterをC-c <letter>、そしてそれ自体がC-c mにバインドされているキーセット"my-bindings" (プレフィックス)にバインドする。基本的にどのキーを使うか忘れたときにC-c mを押下すれば、which-keyがわたしのすべてのバインディングを表示するという訳だ(C-cでも表示はされるがモードのコマンドと混ざって表示されるのであまり役に立たない)。

u/luiggioasis

🔗

Votes 8

vertical、elm、ivy、company等色んな補完フレームワークを耳にするが、どう扱えばよいのだろう。

init.elにcompanyの設定はあったと思うが、実際に使っているかどうかは怪しいもんんだ(実際には気づかないだけで使っているんだろうけど)。でもどこでも目にするのは何故だろう?
emacsスレでは最低でも2回は言及されている。

u/pedzsanReddit

🔗

Votes 8

今週はEmacsのinitファイルの整理に勤しんだが、その途中でこの小さな宝石に出会った。わたしがこれを最初に必要とした場所に因み、わたしは"ZSHのmanページ検索モード(ZSH
man page search mode)"と呼んでいる。

わたしは非常に頻繁にM-x man zshall(1)する(そして全ページを見れるようにwidenするのを忘れる)。そして調べたいことの検索を開始するのだ。manページはいい感じに構造化されているので、"foo"を検索すれば"foo"に関数多くの事項がヒットする。ここで見つけたかったのは、"foo"が記述された場所だ。

この何でもない検索がミソだ。これは多分別のmanページでも役に立つと思うが… わたしは"ZSHのmanページ検索"と呼んでる。

試してみて!

  (defun zsh-manpage-search-regexp (string &optional lax)
"zshall(Zシェルのメタmanページ)のmanページエントリーを検索する文字列をリターンする"
(format "\n[A-Z ]*\n \\{7\\}%s%s" string (if lax "" "\\_>")))

  (isearch-define-mode-toggle zsh-manpage "z" zsh-manpage-search-regexp "\
  概念が記述されているzshallmanページを検索する")

u/trae

🔗

Votes 8

やあ同志諸君、

以下みたいなことができるパッケージはコードスニペットを知らないか:

  1. フレームをポップアップして
  2. 任意のコードを実行してから
  3. フレームを閉じるような補完インターフェイス

emacs-everywhereの類いなんだが、任意のコードを実行できるやつだ。

訳者追訳

meainより
`emacsclient -ce "command"`コマンドじゃダメかい?

traeより
素晴らしい、`-c`フラグを知らなかった。コマンド実行後にさっぱりフレームを始末するアドバイスあるかな

Hammar_Mortyより
`(progn (a-function) (delete-frame))`みたく最後のコマンドとして`(delete-frame)`を呼ぶかな?

u/WorldsEndless

🔗

Votes 8

最近のワイドスクリーンで利用可能なすべての領域にバッファーを分割して読むのに、Emacsビルトインのfollow-modeコマンドを使っている。このモードではパネル間の同期はお互いに保たれるのだ。

img

u/HM0880

🔗

Votes 8

Orgでインラインコードには~、モノスペースのテキストに=を使う理由ってなんだろう?(わたしの知る限り)OrgのレンダーはLaTeX、PDF、HTMLではコードとモノスペースを同じ方法で用いるし、(~と違い)=はSHIFTを押下する必要がないので、わたしはどちらにも=を使っている。

u/sauntcartas

🔗

Votes 8

org-modeの長いチェックボックスリストから、まだ未チェックのアイテムをランダムに選択したいときがある。最近それを助ける小さなヘルパー関数をでっち上げた:

(defun random-choice ()
  (interactive)
  (let ((n 0)
        (selected nil))
    (while (search-forward-regexp (rx point "- [" (group nonl) "]" (+ nonl) "\n") nil t)
      (when (and (string= " " (match-string 1)) (zerop (random (setq n (1+ n)))))
        (setq selected (match-beginning 0))))
    (if selected
        (goto-char selected)
      (error "No unfinished choice found"))))

u/isamert

🔗

Votes 8

sshではなくhttpsでcloneしてしまうことがあるので、それの修整用だ:

(defun isamert/git-origin-switch-to-ssh ()
  (interactive)
  (when-let* ((https-origin (s-trim (shell-command-to-string "git config --get remote.origin.url")))
              (it (s-match "https://\\(.*\\)\\.\\(com\\|net\\|org\\)/\\(.*\\)" https-origin))
              (ssh-origin (format "git@%s.%s:%s" (nth 1 it) (nth 2 it) (nth 3 it))))
    (shell-command-to-string (format "git remote set-url origin %s" ssh-origin))))


github/gitlab等で機能する。規則的に当てはまらないアドレスで動作させる場合には、regexpの拡張が必要だろう。

u/khourhin

🔗

Votes 8

magit
forgeからプルリクができることを発見した。fork元とforkのセットアップでいくつか問題もあったが、既存のissueが解決に役に立った。リモートの名前を扱う方法も改善された。

本当に素晴らしい。Magit/ Magit forgeに感謝だ!

\** u/slinchisl
🔗
\*Votes* 8

わたしの前回の投稿で触れたarxiv-citationがMELPAに入った!
arXivから文献ページをダウンロードする習慣があれば是非試してもらいたい(数学であれば、これらの文献を実際のジャーナルに文献にする ことも可能だ)!

このノートではXMonadからEmacsを呼び出すことについても触れている。投稿自体が実際にEmacsと関係がある訳ではないのでこのsubredditに投稿するほどではなかったかもしれないが、役に立つと思ってくれるXMonadユーザーがいるかもしれないので投稿した次第だ。

u/diamondnbond

🔗

Votes 8

最近見つけたengine-mode

u/mmarshall540

🔗

Votes 8

isearchにまつわる、マイナーだがよくある不満点にたいする小さな解決策を紹介しよう。

要約:StackExchangeの古い投稿

typoを修整したくてバッファーの正確な位置に移動したいことがよくある。その位置がポイントの前にある場合(通常typoに気づくのは入力して暫く後だ)には、isearch-backwardが良好に機能する。"C-r"を押下してからその位置がカレント位置になるまで、目標とするtypoの先頭数文字をタイプすればその位置に移動できるだろう。目標位置にカーソルがジャンプしたら、たとえば"C-t"のような編集コマンドでisearchを自動的に抜けることができる。かわりにisearch-modeを抜けるのに"C-m"を使えば、その位置でテキストの挿入が開始できる。素晴らしい!

しかし目標がポイントよりにある場合には、多少完璧さに欠ける。目標先頭にポイントを置くisearch-backwardと異なり、isearch-forwardは検索結果の終端にポイントを配置するせいだ。

目標の手前にある任意の数文字で検索を開始することもできるだろう。しかしどの位の個数の文字通りを使うか決める必要があるし、十分な文字数を使用しなければ大量の結果がヒットしてしまう。結果が十分に絞り込まれるまで目標の文字数以上をタイプしても、望んだ位置にポイントが置かれることはない。

別の手として、後方に検索する際と同じことを行うのはどうだろう。目標の文字のタイプを開始したら、目標位置が選択されるまで文字をタイプするだけだ。しかし今度ははあなたの望んだ位置ではなく、ポイントが結果の終端に配置されるだろう。"M-b"で検索を抜けて単語の先頭にポイントを移動するが、これは検索結果に単語境界が含まれていないことを前提としており、実際の目標は常に単語の先頭という訳にはいかない。単語の途中のどこかであることも多々あるだろう。

かわりにC-rでポイントを結果の先頭に移動することもできる。しかしその位置でテキストの挿入を開始するためには、C-mで検索を抜ける必要がある。特に明記していなかったが検索を開始するために何かキーを押下する必要はないが、検索を終えるためにはキーを2回押下する必要がある。

これを訂正するのが以下のコードだ。

(defun my/isearch-bor-exit ()
  "isearchの結果の先頭にポイントがあるか確認してからexitする"
  (interactive)
  (when (< isearch-other-end (point))
    (goto-char isearch-other-end))
  (call-interactively 'isearch-exit))
    
(define-key isearch-mode-map ?\M-m 'my/isearch-bor-exit)

これで正確な位置(ただの単語検索ではない)への移動には、まずisearchで目標位置の先頭にある文字のタイプを開始、タイプした文字列が結果の一部になったらタイプを止めて、"M-m"を押下すれば検索を終了して修整を開始できるようになった。前進か後退、isearch終了前にポイントを戻すべきかどうかを判断するために思考停止しなくても済む。

地味でとてもシンプルな解決策だが、一旦止まって問題解決できたのが嬉しい。

今は以前にAvyを使っていたときと同じくらい、isearchを多用していると思う。数多の理由により依然としてAvyは偉大である。isearchの結果が大量にあり絞り込むために多くのタイピングが必要な際にとりわけ便利なのがavy-isearchだ(これは常に結果の先頭にポイントを配置する;
結果の終端になることは絶対にない)。

u/PriorOutcome

🔗

Votes 8

あるyasnippetsで別のyasnippetsを展開できるようにしたい(TABでsnippetを展開するのではなく次の位置に移動したい)。驚いたことに以下だけで行うことができた:

:bind ("C-<tab>" . yas-expand)

C-はsnippet内でsnippetを展開するので、すべてわたしの望み通りだ。ネストされたsnippetの場合にはで次のsnippetに移動するだけだ。

u/[あぼーん]

🔗

Votes 8

bs-showは興味深いコマンドだ。オープン中のバッファーに手早くアクセスできるポップアップ風のバッファーを表示するのだ。カスタマイズ可能なオプション、便利なバインディングが山ほどある。list-buffersibufferのかわりに試してみたが、非常に高速だし気に入っている。

u/rberaldo

🔗

Votes 8

小さな気づきを1つ: tex-modeではC-c C-eで新たな環境を作成できる。ユニバーサル引数を使えば(C-u C-c C-e)、ある環境を別の環境に簡単に変更できる。

環境のenumerate(箇条書き)を作り、すぐ気がかわった。直感にしたがい上述のコマンドの作成を試みているときに、環境をitemize(箇条書き)に変更できるようになったのだ。

編集: markdown

u/TVerron

🔗

Votes 8

(何も派手なことはないし多くの人たちの道具箱には、似たものがあるだろうと確信しているが、今日改めて便利だと思った。)

elispパッケージの記述では、コンパイラーはすべての変数と関数が宣言されていることを期待するだろう。どこか別の場所で定義されている変数の定義は簡単だ。変数をdefvarするだけである。一方関数の宣言では、その関数が定義されているファイルを明示する必要がある。

これらすべてのフォームの挿入は面倒だし、それが複数ファイルを含むパッケージ由来であれば尚更面倒だ。しかしEmacsはこれらの関数がどこにあるか承知しているので、単にそれを尋ねるだけで事足りる。

(defun tv/add-declare-function (fun)
  (interactive "a") 
  (let* ((buf (car (find-function-noselect fun))) 
         (name (file-name-base (buffer-file-name buf)))) 
    (insert (format "(declare-function %s "%s")\n" fun name))))

これをM-xで呼び出して宣言したい関数の名前(補完サポートあり)を挿入すればどうだろう。

u/tryptych

🔗

Votes 8

同僚が見せてくれたのはIntelliJの"クリップボードとの比較"の機能だ。これはとても優れた機能だ。リージョンを選択してcompare-with-clipboardを呼び出せば、選択間でのdiffが入力できる。

同様なものの実装にはそれほど時間はかからなかった:

(defun ediff-compare-region-clipboard (begin end)
  (interactive "r")
  (save-excursion
    (let ((selected-region (buffer-substring begin end))
          (clipboard-buffer (get-buffer-create "*ediff-clipboard*"))
          (region-buffer (get-buffer-create "*ediff-region*")))
      (with-current-buffer clipboard-buffer
        (insert (car kill-ring)))
      (with-current-buffer region-buffer
        (insert selected-region))
      (ediff-buffers clipboard-buffer region-buffer))))

しかしこれでも理想は満足していない。特に"クリップボード"に挿入する優れた方法は存在するのだろうか?
すぐに思いついたのは比較用にリージョンをコピーするという方法だが、その後に多くの編集コマンドもkillリングに追加していくだろう。そのために処理のこの部分はinteractiveにしたかった。

u/[あぼーん]

🔗

Votes 8

わたしは補完にorderlessを使っているが、たとえばイニシャルだけでファイルを絞り込んで、イメージのようなことを行いたい場合もある。これを行うには大文字小文字は無視して、ミニバッファーでイニシャルで問い合わせを行えばよい。

(use-package orderless
      :ensure t
      :custom
      (completion-styles '(orderless))
      (completion-category-defaults nil)
      (read-file-name-completion-ignore-case t)
      (completion-category-overrides '((file (styles partial-completion))
    				   (minibuffer (initials)))))

u/slinchisl

🔗

Votes 8

非常にシンプルだがこれのお陰で"またこれを行わなければならないのか?"というシチュエーションの多くから救ってもらった。

LaTeXファイル記述の際に数式の表示が"もっと目立つ"ように、インライン数式に変換する場合が頻繁にあることに気がついた。他に実装済みのものも見つからなかったので、ポイントがインライン数式の環境
(基本は$によるインライン数式だが$$は使わない):

(defun slot/inline-to-display-math ()
  "インライン数式からディスプレイ数式に変換"
  (interactive)
  (when (and (texmathp) (equal "$" (car texmathp-why))) ; インライン数式か?
    (let* ((beg   (save-excursion (search-backward "$")))
           (end-$ (search-forward "$"))
           (end   (if (-contains? '(?. ?,) (char-after end-$))
                      (1+ end-$)    ; ディスプレイ数式に句読点を配置
                    end-$)))
      (kill-region beg end)
      ;; ディスプレイ数式を挿入
      (TeX-newline)
      (insert "\\[")
      (TeX-newline)
      (insert-for-yank (string-replace "$" "" (current-kill 0)))
      (TeX-newline)
      (insert "\\]")
      (TeX-newline))))

たとえば以下のようなインライン数式は

The cowedge $\iota \colon P \xRightarrow{\; .. \;} C$ is easily seen to be
unique up to unique isomorphism.

以下に変換される

The cowedge
\[
  \iota \colon P \xRightarrow{\; .. \;} C
\]
is easily seen to be unique up to unique isomorphism.

$$ $$ベースのシンプルなディスプレイ数式に何か文字列を挿入する関数が見つからなかったのは驚きだった。かわりに見つかったのは$に挿入するバージョンだけだった。displaymath環境の挿入も可能だろうが見た目がアレなので、まあしょうがないか。

u/oantolin

🔗

Votes 8

これは需要はほとんどないだろうが、わたしのワークフローを目に見えて改善したので共有しておこう。PDFでフォームを受け取るのだが、それが記入可能なPDFではなく単に紙のフォームをスキャンしただけのPDFのときだ。理性のある人ならばGimpの類いをインストールするのだろうが、わたしはPDFフォームに\includegraphicsを使ってLaTeXで記入、それがトップになるようにtextposパッケージを使っている。

これにはテキストを配置するための座標が必要だが、わたしはトライアンドエラーでこなしていた。通常ならマウスは好みではないが、イメージ内のポイント指定に使用する入力デバイスとしてはキーボードより優れていると認めざるを得ないだろう。そのためにPDF内のポイントをクリックしたらカレントバッファーにポイント位置のcm座標を挿入する関数を記述することにした。これは非常に簡単に記述できた。これはEmacs、Lispマシン、あるいはSmalltalkのようなシステムの強力さを示す事例だろう。何かの機能が必要になったら、それを実装するコードを簡単に見つけることができるのだ。pdf-toolsにはマウスクリックをPDFのドキュメント座標に変換するコードが含まれていなければならない筈だ。なぜなら注釈の配置はマウスのクリックで行うのだから。注釈用の関数はa tにバインドした筈であり、後でC-h k使えばソースコードを手早く確認できるのだ。このような次第で以下の関数の記事はとても簡単だった:

(defun insert-coordinates ()
  "マウスがクリックした座標(cm)を挿入する"
  (interactive)
  (let ((pos (event-start (pdf-util-read-click-event "Click on PDF"))))
    (insert
     (with-selected-window (posn-window pos)
       (let ((pt (pdf-util-scale-pixel-to-points (posn-object-x-y pos))))
         (cl-flet ((f (x) (* 2.54 (/ x 72.0))))
           (format "(%.1fcm,%.1fcm)" (f (car pt)) (f (cdr pt)))))))))

u/Bodertz

🔗

Votes 8

概要:

タイトルにある&c.etc.の略なのは明らかだろう。スライドバーではこの種の過去スレッドへのリンクはredditの検索であり、この検索には検索用語としてetc.は含まれているが&c.,は含まれていないのでスレッドが表示されない。

u/jumpUpHigh

🔗

Votes 8

freenodeからlibrea.chatへの進行中の以降を考慮して、oftcのdebian
チャンネル接続時にはercをn回行っている。自動的に認証して欲しいがしてくれない。相変わらずmsg NickServ IDENTIFY mypassとタイプする必要があるのだ。どうすればいいか判る人いる?

(use-package erc
  :custom
  (erc-autojoin-channels-alist '(("OFTC" "#debian" )))
  (erc-prompt-for-nickserv-password nil)
  (erc-prompt-for-password nil)

  :config
  (add-to-list 'erc-modules 'services)
  (erc-update-modules)
  (erc-autojoin-enable)
  (defun erc-start()
    "Start ERC."
    (interactive)
    (erc :server "irc.oftc.net" :nick "mynick"))
) 

それとファイル~/.authinfoには自分のエントリーを用意しておく

machine irc.oftc.net login "mynick" password "mypass"

追記: 使っているのはGNU Emacs 27.1だ

u/a-k-n

🔗

Votes 8

--with-mac-metalでEmacsのMacポートをhomebrewのFormulaをインストールすると、Emacsの性能が有意に改善されることが判った。バッテリーも快適だ!

u/[あぼーん]

🔗

Votes 8

helm-aproposですべてのhelp関数をhelpfulモードで完全にオーバーライドしたければ、以下をコンフィグに追加してみてはどうだろう:

(advice-add 'describe-function :override #'helpful-function)
(advice-add 'describe-variable :override #'helpful-variable)
(advice-add 'describe-command  :override #'helpful-callable)
(advice-add 'describe-key      :override #'helpful-key)
(advice-add 'describe-symbol   :override #'helpful-symbol)

u/w0ntfix

🔗

Votes 8

わたしのデビューパッケージがmelpaから出たぞい!

u/StrangeAstronomer

🔗

Votes 8

以下はとてもシンプルではあるが、わたしにとってはかけがえのないスニペットだ。

buffer-menu (C-x
C-b)でC-uを使えば*Messages*のようなスペシャルバッファーが表示されなくなることに気づくのにおよそ30年の時間を費やした。用途のほとんどを占めていたファイル切り替えの際の混乱が軽減された。

更に数年を経て、ついにわたしは自分の望んでいたモードを見い出した。逆転するのだ。そしてC-x
C-bではファイルだけ、C-uのプレフィックス付きで呼び出すとスペシャルバッファーも一緒に表示するようになった。馬鹿らしい取るに足らない小技だが、わたしにとっては最高である。

(global-set-key (kbd "C-x C-b")
                '(lambda (&optional arg)
                   "buffer-menuを実行ただしC-uは逆の意味(C-u未指定ならファイルだけ)"
                   (interactive "P")
                   (setq arg (not arg))
                   (buffer-menu arg)))

u/geza42

🔗

Votes 8

C/C++モードに入るスマートな関数を作った。以下の通りだ:

for/if/else/switch上でキーを押下すれば{.、空行、}を配置してbody部分にカーソルを移動する(その行にカーソルがあるかどうかは関係ない)。struct/classの上で押下すると、前の場合と似ているが行の終端へのセミコロン配置も行う。それ以外の場合には;、もしすでに{;、空行があれば改行を配置する。コメントの中ではコメントを継続せずにインデントされた行を配置する(RETでコメントを継続するように設定してあるので、コメントのクローズにはM-RETを使用する)。

smartparenでは毎回)でクローズする必要がないので役に立つだろう。たとえばifを記述すると、カーソルが|だとしてクローズする)が自動的に挿入される。


その後にM-RETを押下すれば以下のような結果が得られる筈だ:

if (expr) {
    |
}

これを作って以来{};を押すことはほとんどなくなった。

関数シグネチャーでは宣言(終わりが;)か定義({ }で終わる)かを判断できないので;を置くようにしている。関数のパラメータ(force-curly)は{を強制的に配置する(わたしはM-S-returnにマップしている)。

コードは以下だが、まだ改善の余地がたくさんあるかもしれない:

(defun my-cc-mode-M-RET-context (force-curly)
  (let ((c
         (if force-curly 'curly
           (let ((s (syntax-ppss)))
             (cond
              ((nth 4 s) 'comment)
              ((and (eolp) (looking-back "[{;]")) 'nop)
              ((save-excursion
                 (skip-syntax-forward " ")
                 (looking-at "\\(for\\|if\\|switch\\|else\\|do\\)\s?")) 'curly)
              ((save-excursion
                 (skip-syntax-backward " ")
                 (skip-syntax-backward "w")
                 (looking-at "\\(for\\|if\\|switch\\|else\\|do\\)\s?")) 'curly)
              ((save-excursion
                 (when (nth 3 s) (skip-syntax-backward "^\"") (backward-char))
                 (skip-syntax-backward " ")
                 (if (looking-back ")")
                     (backward-sexp)
                   (ignore-errors (backward-up-list)))
                 (skip-syntax-backward "(")
                 (skip-syntax-backward " ")
                 (looking-back "for\\|if\\|switch")) 'curly)
              ((save-excursion
                 (skip-syntax-forward " ")
                 (looking-at "struct\\|class")) 'curly+semicolon)
              ((save-excursion
                 (skip-syntax-backward " ")
                 (skip-syntax-backward "w")
                 (if (looking-at "struct\\|class") t
                   (skip-syntax-backward "w")
                   (skip-syntax-backward " ")
                   (looking-back "struct\\|class"))) 'curly+semicolon)
              (t 'semicolon))))))
    (cond
     ((or (eq c 'curly) (eq c 'curly+semicolon))
      (save-excursion
        (end-of-line)
        (if (looking-back "{")
            'nop
          c)))
     ((eq c 'semicolon)
      (save-excursion
        (end-of-line)
        (if (looking-back ";")
            'nop
          c)))
     (t c))))
    
(defun my-cc-mode-M-RET (force-curly)
  (let ((c (my-cc-mode-M-RET-context force-curly)))
    (cond
     ((eq c 'nop)
      (if (save-excursion
            (forward-line)
            (beginning-of-line)
            (looking-at-p "[[:space:]]*$"))
          (progn
            (forward-line)
            (c-indent-line))
      (end-of-line) (newline-and-indent)))
     ((eq c 'comment) (newline-and-indent))
     ((eq c 'semicolon)
      (end-of-line)
      (self-insert-command 1 ?\;)
      (newline-and-indent))
     ((eq c 'curly)
      (save-excursion (end-of-line) (unless (looking-back "\s") (insert " ")) (insert "{") (newline-and-indent) (insert "}") (c-indent-line))
      (end-of-line)
      (newline-and-indent))
     ((eq c 'curly+semicolon)
      (save-excursion (end-of-line) (unless (looking-back "\s") (insert " ")) (insert "{") (newline-and-indent) (insert "};") (c-indent-line))
      (end-of-line)
      (newline-and-indent)))))
    
(define-key c-mode-base-map (kbd "M-RET") (lambda () (interactive)
(my-cc-mode-M-RET nil)))
(define-key c-mode-base-map (kbd "<M-S-return>") (lambda () (interactive)
(my-cc-mode-M-RET t)))

u/[あぼーん]

🔗

Votes 8

ちょっとした注釈付けやselectrummarginaliaを試しているが、いい感じで動いてる。ミニバッファーにコマンドにキーバインディングを表示するんだ。頻繁に使わないのでキーバインディングを覚えていないモードでは特に重宝している。

u/martinslot

🔗

Votes 8

もっと寛いで操作できるようにeshellをカスタマイズしてみた。エイリアスもいくつか設定している。

あなたのeshellはどんな感じかな?

u/[あぼーん]

🔗

Votes 8

[あぼーん]

u/adt7799

🔗

Votes 8

わたしには役に立っている。

別のプログラムからEmacsに切り替えるときにバッファーを複数オープンしていると、どこバッファーにカーソルがあるのかいつも戸惑ってしまう。なので以下のようなマッピングを作成してみた

(global-set-key (kbd "M-l") 'beacon-blink)

u/[あぼーん]

🔗

Votes 8

[あぼーん]

u/ji99

🔗

Votes 8

Googleの検索の提案候補にHippie-expandする。全体的にshell-parse.elからのインスパイアされて作った。

わたしはhippie-expand-try-functions-listの最後にtry-expand-google-completionを追加している。

(defun google-suggest--request (query)
  (with-current-buffer
      (url-retrieve-synchronously
       (format "http://suggestqueries.google.com/complete/search?client=firefox&q=%s" query) t t 1)
    (goto-char (point-min))
    (re-search-forward "^$")
    (delete-region (point)(point-min))(buffer-string)))
    
(defun google-suggest--list (result)
  (let* ((q (progn
              (string-match ",\\[\\(.*?\\)\\]" result)
              (match-string 1 result)))
         (r (replace-regexp-in-string "\\\"" "" q))
         (l (split-string r "," t)))
    (when (> (length (car (cdr l))) 0)
      (remove
       (car l)
       (cdr l)))))
    
(defun try-expand-google-completion (old)
  (unless old
    (he-init-string (hippie-word-bg) (point))
    (setq he-expand-list (sort
                          (all-completions
                           he-search-string
                           (lambda (s y n) (google-suggest--list (google-suggest--request s))))
                          'string-lessp)))
  (if (null he-expand-list)
      (progn
        (when old (he-reset-string))
        ())
    (he-substitute-string (car he-expand-list) t)
    (setq he-tried-table (cons (car he-expand-list) (cdr he-tried-table)))
    (setq he-expand-list (cdr he-expand-list))
    t))

訳者追訳

ji99より

動作させるためには、これも投稿する必要があったようだ:

(defun hippie-word-bg ()
  (let ((p))
    (save-excursion
      (backward-word 1)
      (setq p (point)))
    p))

u/WorldsEndless

🔗

Votes 8

レジスターだ:
Emacsに最初からあり、シンプル過ぎて忘れてしまう信じられないほど役に立つ機能だ。テキストの保存、ウィンドウや位置の保存で重宝している。https://orys.us/tv

u/aartist111

🔗

Votes 8

M-x ibuffer/ cを見つけた。バッファーを内容でフィルターするのだ。grep -cと少し似ている。内容で覚えている数単語から素早くファイルを見つけるのに非常に役に立っている。これまではファイル名かモードだけでファイルを探していた。

u/hairlesscaveman

🔗

Votes 8

Magitを使っていてブランチを作成するときには、{ticketnumber}-{short-description}という形式にしたがってブランチ名を作成している。しかしブランチに説明的な名前をタイプする際に、ついセンテンス記述時の手癖で単語区切りにダッシュではなく"SPC"をタイプしてしまうことがよくある。そして"Whitespace
isn't allowed here"の警告によって、流れが中断されてしまうのだ。

以下は警告を抑止してスペースが押下されたらダッシュを挿入するadviceだ。

(advice-add 'magit-whitespace-disallowed
            :around
            (lambda
              (orig-fun &rest args)
              (interactive)
              (insert "-")))

u/karthink

🔗

Votes 8

AucTexユーザーへ:
CDLatexを使わないのは損だ。これは一種のスニペットテンプレートであり、主にLaTeX向けの高速入力を目的としたツールである。LaTeX用にセットアップしたYasnippetテンプレートとの違いは、CDLaTeXのTABキーならスニペットのエントリー中だけではなく、いつでも前の項目にジャンプできる点だ。口で説明するのは難しいので、デモンストレーションをお見せしよう:

  1. CDLatexとpreview.elによる高速入力
  2. キー表示付き高速入力

少し長めだがAucTexをどうやってセットアップしたかについても最近投稿した。

CDLaTeXはCarsten
Dominik氏によって記述されているが、彼はOrg-modeやreftexの作者でもある。したがってOrgにはこれらの機能をorg-modeで利用可能にするマイナーモードのorg-cdlatexが同梱されている。

u/[あぼーん]

🔗

Votes 8

わたしがEmacsを使い始めたときにとても助けになったのはA beginers guide to emacs 24 or later by sasha
chua
だ。

u/ji99

🔗

Votes 8

素晴らしいウェブブラウザLinksのための基本的なインターフェイスだ:

(defun links-browser (&optional link new-window)
  (interactive)
  (unless link
    (setq link (read-from-minibuffer "url: ")))
  (make-process
   :name "links-browser"
   :connection-type 'pipe
   :command (list "links" "-g" link)))
    
(defun links-search (&optional query)
  (interactive)
  (unless query
    (setq query (read-from-minibuffer "search query: ")))
  (pcase query
    ((pred (string-match "\\~d .*"))
     (links-search--launch "dict" (substring query 2 nil)))
    ((pred (string-match "\\~b .*"))
     (links-search--launch "book" (substring query 2 nil)))
    ((pred (string-match "\\~w .*"))
     (links-search--launch "wiki" (substring query 2 nil)))
    ((pred (string-match "\\~m .*"))
     (links-search--launch "imdb" (substring query 2 nil)))
    ((pred (string-match "\\~y .*"))
     (links-search--launch "yout" (substring query 2 nil)))
    ((pred (string-match "\\~t .*"))
     (links-search--launch "thes" (substring query 2 nil)))
    ((pred (string-match "\\~s .*"))
     (links-search--launch "syno" (substring query 2 nil)))
    (_ (links-search--launch "seax" query))))
    
(defun links-search--launch (engine query)
    (pcase engine
      ("dict" (links-browser (format "https://en.wiktionary.org/wiki/Special:Search?search=%s" query)))
      ("wiki" (links-browser (format "https://en.wikipedia.org/w/index.php?title=Special:Search&search=%s&go=Go" query)))
      ("imdb" (links-browser (format "https://www.imdb.com/find?s=all&q=%s" query)))
      ("yout" (links-browser (format "https://www.youtube.com/results?search_query=%s" query)))
      ("book" (links-browser (format "http://gen.lib.rus.ec/search.php?req=%s&res=100&sort=id&sortmode=DESC" query)))
      ("thes" (links-browser (format "https://www.powerthesaurus.org/%s" query)))
      ("syno" (links-browser (format "https://duckduckgo.com/lite/?q=%s site:macmillandictionary.com" query)))
      ("seax" (links-browser (format "https://search.snopyta.org/?q=%s" query)))))

u/[あぼーん]

🔗

Votes 8

わたしのワークフローを改善したトリックを2つほど:

  1. (setq process-adaptive-read-buffering nil)EATがかなり高速化された!
  2. (setq eglot-events-buffer-size 0)(fset #'jsonrpc--log-event #'ignore)、それにeglot-boosterでeglotがかなり高速化された!

u/[あぼーん]

🔗

Votes 8

わたしが見つけてクールだと思ったことの1つに、 端末版のEmacsでSuperやHyper
といった修飾キーを実際に使えることだ。SSH経由でも機能するし、init.elの変更も不要だ。

EmacsにあるSuper修飾キーをエミュレートするC-x @ s、Hyper修飾キーをエミュレートするC-x @ hといったビルトインのキーバインディングがトリックのネタだ。たとえばC-x @ s aを押せば、EmacsがそれをSuper+aと解釈するのだ。

たとえばKittyのようななら何か実行したいことをSuper+aにバインドすれば、それをマップするだけでEmacsが期待するキーシーケンスを送信できるだろう。kitty.confに追加するだけである:

map super+a send_key ctrl+x @ s a map super+b send_key ctrl+x @ s b ...

一丁あがりだ。emacs -nwでSuperが機能するようになった!
Kittyがs-aを通常の端末をサポートするコントロールキーバインディングC-x @ s aに変換して、Emacsがそれをs-aに変換し直すのである。

u/hunajakettu

🔗

Votes 8

Windows技術において唯一わたしの正気を保ってくれるものだ。

u/habamax

🔗

Votes 8

スクショをたくさん貼ったシンプルなマニュアルをorgでよく作成する。

そこでWindowsとLinux(waylandのwl-pasteが必要)の両方で動作するorg/insert-screenshotコマンドを作った:

(defun org/insert-screenshot ()
  (interactive)
  (let* ((img-dir (concat "img-"
                          (file-name-sans-extension (buffer-name))))
         (img-name (concat (file-name-sans-extension (buffer-name))
                           "-" (format-time-string "%Y%m%d-%H%M%S") ".png"))
         (filename (concat img-dir "/" img-name)))
    (make-directory img-dir :parents)
    ;; Windows -- powershellを使用、その他(つまりlinux) -- wl-pasteを使用
    (shell-command
     (if (eq system-type 'windows-nt)
         (concat
          "powershell -command \"Add-Type -AssemblyName System.Windows.Forms;"
          "if ($([System.Windows.Forms.Clipboard]::ContainsImage()))"
          "{$image = [System.Windows.Forms.Clipboard]::GetImage();"
          "[System.Drawing.Bitmap]$image.Save('"
          filename
          "',[System.Drawing.Imaging.ImageFormat]::Png);}\"")
       (concat "wl-paste > " filename)))
    (insert (concat "[[file:" filename "]]"))))
    

以下のようなフローだ:

  1. OS<機能でスクショ作成
  2. orgドキュメントに移動(たとえばdoc1.org)
  3. M-x org/insert-screenshot RET
  4. ./img-doc1/doc1-20230525-100621.pngにイメージファイルが保存される
  5. リンクがorgドキュメントに挿入される

u/swhalemwo

🔗

Votes 8

最近数字をたくさん含んだレポートの記述を開始した。それらの数字の多くはバージョンの更新にしたがって変更される。これらの数字を手作業で更新する手間を省きたいので自分のRスクリプトからマクロを生成できること値をマクロテキストにではなく表示できること、それらを少ないキーストロークでorg-macro-templatesからconsult--readに渡す方法を調べた。数時間を要したが、将来的には時間の節約になればいいな!

u/sebasTEEan

🔗

Votes 8

今朝のプレゼンでファイルを使いたいが、IPアドレスとパスワードというセンシティブな情報が含まれているファイルだ。以下はバッファーの機密部分を非表示にするコードだ:

(defun sm/hide-ip-addresses ()
  "バッファー内のIPアドレスをマスク"
  (interactive)
  (let ((ipv4-regex "\\b\\(?:[0-9]\\{1,3\\}\\.\\)\\{3\\}[0-9]\\{1,3\\}\\b")
	(ipv6-regex "\\b\\(?:[0-9a-f]\\{1,4\\}:\\)\\{7\\}[0-9a-f]\\{1,4\\}\\b\\|\\b\\(?:[0-9a-f]\\{1,4\\}:\\)\\{1,6\\}\\(:[0-9a-f]\\{1,4\\}\\)\\{1,6\\}\\b"))
(save-excursion
  (goto-char (point-min))
  (while (re-search-forward ipv4-regex nil t)
	(let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
	  (overlay-put overlay 'hidden-text t)
	  (overlay-put overlay 'display "***.***.***.***"))))
(save-excursion
  (goto-char (point-min))
  (while (re-search-forward ipv6-regex nil t)
	(let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
	  (overlay-put overlay 'hidden-text t)
	  (overlay-put overlay 'display "****:****:****::****"))))))

(defun sm/hide-passwords ()
  "バッファー内のパスワードをマスク"
  (interactive)
  (let ((pwd-regex ".*passwor[dt]*:\\(.*\\)"))
(save-excursion
  (goto-char (point-min))
  (while (re-search-forward pwd-regex nil t)
	(let ((overlay (make-overlay (match-beginning 1) (match-end 1))))
	  (overlay-put overlay 'hidden-text t)
	  (overlay-put overlay 'display "******"))))))

(defun sm/hide-secrets ()
  "バッファー内のIPアドレスとパスワードをマスク"
  (interactive)
  (sm/hide-ip-addresses)
  (sm/hide-passwords))

(defun sm/remove-overlays ()
  "バッファー内で`hidden-text'プロパティをもつオーバーレイを削除"
  (interactive)
  (dolist (overlay (overlays-in (point-min) (point-max)))
(when (overlay-get overlay 'hidden-text)
  (delete-overlay overlay))))

u/[あぼーん]

🔗

Votes 8

[あぼーん]

u/konrad1977

🔗

Votes 8

昨日ワンライナーを思いついたので、 Evil:configセクションに追加した。

追加した(define-key evil-visual-state-map (kbd "u") 'undo)のお陰で選択したリージョン内のアンドゥができるようになった。魔法みたいだ。

\** u/slinchisl
🔗
\*Votes* 8

どちらかと言えばXMonadユーザー向けなのでトップレベルとして価値がある投稿ではないかもしれないが、彼らがEmacsのユーザーでもあることは珍しくないし、XMonadのorg-mode統合の使用によってアイデアの素早いキャプチャが如何に容易になるか知って喜んでくれる人も数人はいるかもしれない!

u/poinkalum

🔗

Votes 8

masterに追随していれば、M-X(大文字の"X"だ)を使って非常に役に立つコマンドexecute-extended-command-for-bufferを使用できる筈だ。これはLarsが投稿したブログ記事に記されている挙動を実装するコマンドだ。

u/ji99

🔗

Votes 8

わたしが補完で必要とするすべてだ:

(use-package icomplete
  :bind
  (:map icomplete-minibuffer-map
        ([C-return] . exit-minibuffer)
        ([return] . minibuffer-try-complete-and-exit))
  :config
  (defun minibuffer-try-complete-and-exit ()
    (interactive)
    (minibuffer-force-complete)
    (setq-local deactivate-mark nil)
    (throw 'exit nil))
  :hook (after-init . icomplete-mode))
    
(use-package orderless
  :ensure t
  :custom
  (completion-styles '(orderless))
  (orderless-matching-styles 'orderless-literal))

u/oantolin

🔗

Votes 8

dabbrev-expand
(デフォルトでM-/にバインドされている)を使うのが好きだ。バッファーのいずれかにあることが判っているテキストの補完に使っている。一度に1つの単語を補完するが、補完が見つかった位置から更に後続の単語の補完を続けたければ、スペースを挿入してからもう一度dabbrev-expandを実行するか、あるいはSPC M-/で続けて補完できるだろう。

たとえばどこかのバッファーに"The quick brown fox jumps over the lazy
dog"というテキストがあり、(他に"qu"を含んだバッファーはないものとする)、qu M-/ SPC M-/ SPC M-/によって"quick
brown fox"が挿入されるだろう。

これだけでも素晴らしいのだが、SPC M-/というキーシーケンスがわたしにはしっくりこなかったので、M-'にバインドする小さな関数を記述した:

(defun dabbrev-next (arg)
  "前に展開が見つかった場所から次のARG個の単語を挿入する"
  (interactive "p")
  (dotimes (_ arg)
    (insert " ")
    (dabbrev-expand 1)))
    

すると"quick grown fox"をqu M-/ M-' M-'で得られるようになった。こちらの方がタイプしやすい(わたしのキーボードでは/'は非常に近くにある)。

(M-'のデフォルトではわたしが絶対に使わないabbrev-prefix-markにバインドされているので、リバインドすることに躊躇う理由はなかった。)

u/[あぼーん]

🔗

Votes 8

my-minor-modeという小さなモードを作ってグローバルに有効にする。これのキーマップをプレフィックスなしの自分のキーバインディング用に使用するのだ。それからこのキーマップにプレフィックス話割り当てる。この方法を使えば、必要ならキーバインディングのほとんどを無効にしたり、プレフィックスキーを(たとえばC-cH-x<menu>等に)簡単に切り替えたり、これらのキーバインディングを複数のプレフィックスで利用できるようにできるし、(define-key my-minor-mode-map <key> nil)で簡単にデフォルトのキーバインディングをリストアできる。以下はわたし用にマイナーモードを定義する場合:

;;; GKマイナーモード:
    
;; このコンフィグの肝となるのがGKマイナーモード。
;; このマイナーモードのキーマップでマッピングされのは
;; グローバルマップからマッピングを除外する一部のキー、
;; および特定のモードのバインディングを除いた、
;; ほとんどすべてのキーバインディングである。
;; ミニバッファーとFundamentalモードを除くすべての場所で
;; 、このマイナーモードはアクティブである。
    
(defgroup GK nil
  "Group for my configuration."
  :group 'emacs
  :prefix "gk-")
    
(defvar gk-minor-mode-map
  (make-sparse-keymap)
  "すべての自分用バインディングを配置するキーマップ")
    
(defvar gk-minor-mode-prefix-map
  (make-sparse-keymap)
  "自分用バインディングのプレフィックスマップ")
    
(fset 'gk-minor-mode-prefix-map gk-minor-mode-prefix-map)
    
(defvar gk-minor-mode-prefix "\C-c"
  "`gk-minor-mode'のためのプレフィックス用キーマップ")
    
(define-minor-mode gk-minor-mode
  "カスタマイズ用のグローバルマイナーモード
    
{gk-minor-mode-map}"
  nil "" gk-minor-mode-map
  (let ((map gk-minor-mode-map))
    (define-key map gk-minor-mode-prefix #'gk-minor-mode-prefix-map)))
    
(define-globalized-minor-mode global-gk-minor-mode gk-minor-mode
  gk-minor-mode)

後はどこかで有効にするだけだ。一度にグローバルモードを有効にするために好んで使っているのが以下のセットアップだ:

;;;; グローバルモード:
    
;; このモジュールははグローバルモードを1つのコマンドで
;; 一度にオン/オフ、登録/登録解除、デフォルトモードを無効にする
;; といったグローバルモード用のユーティリティーを提供する。
    
;; `gk-global-modes`にリストされたすべてのモードは
;; `after-init-hook`で切り替わるので、名前付きフック
;; の実行までにこの変数に加えられた変更によって、
;; 実際にオンにするモードが決定される。
    
;; `gk-disabled-modes`には無効にするモードをリストする。
    
;; これらのリストにはそれぞれ実際のモード関数であるような
;; シンボルが含まる。有効にするリストの場合には`+1`、
;; 無効にするリストの場合には`-1`を引数として呼び出される。
    
;; これをフックとして使用してはならない。
;; かわりに`after-init-hook`を使用すること。
    
(defvar gk-global-modes nil
  "有効にするグローバルモードのリスト")

(defvar gk-disabled-modes nil
  "無効にするグローバルモードのリスト") 
    
(defvar gk-toggle-global-modes nil)
(defun gk-toggle-global-modes ()
  "`gk-global-modes`にリストされたモードを一辺に有効/無効にする"
  (interactive)
  (setf gk-toggle-global-modes (not gk-toggle-global-modes))
  (let (errors)
    ;; グローバルモードを有効にする
    (dolist (mode gk-global-modes)
      (condition-case e
          (funcall mode (if gk-toggle-global-modes 1 -1))
        (error (push ~(,mode ,e) errors))))
    ;; gk-disabled-modesのモードを無効にする
    (dolist (mode gk-disabled-modes)
      (condition-case e
          (funcall mode (if gk-toggle-global-modes -1 1))
        (error (push ~(,mode ,e) errors))))
    (when errors
      (warn "Following errors occurred when activating global modes:\n%S"
            errors))))
    
(add-hook 'focus-out-hook #'garbage-collect)

この関数にはいくつか修整が必要だが、グローバルモードをセットアップするフックとしては良好に機能するだろう。
global-gk-minor-modegk-global-modesに入れて、他のモードと一緒に有効にする。

編集: gk-toggle-global-modesを修整

u/[あぼーん]

🔗

Votes 8

学んだこと:
一部のモードでcompanyを無効にできること。素でシェル補完があるshellやeshellではcompanyの補完が本当に低速なのでこれが必要だったのだ。

(use-package company
  :after ispell
  :diminish
  :config
  .
  .
  .
  (setq company-global-modes '(not eshell-mode shell-mode))
  (global company-mode 1))
  

これで意図した通り動作する。

u/LionyxML

🔗

Votes 8

TUIとGUIの両方で同等のユーザーエクスペリエンスを得るためにわたし自身が使っているEmacsコンフィグのブログ投稿:
https://www.rahuljuliato.com/posts/lemacs

u/agumonkey

🔗

Votes 8

orgファイルのソースブロックにorg-modeのファイルをもつことができる。

u/slinchisl

🔗

Votes 8

Emacs
28のrepeat-modeを少し弄ってみた。修飾キーを押下せずとも、概念的に同じ複数のアクションを連続して実行できるモードだ。如何せんこれらのrepeat用のマップを定義するための人間工学は未成熟なので、マップを定義して関数用に適切なシンボルプロパティをセットする小さいマクロを記述した(実はこれがわたしの正真正銘の処女作だ!)。

(defmacro defrepeatmap (symbol &optional pairs docstring)
  "`repeat-map'を定義するマクロ。
与えられたDOCSTRINGとともにSYMBOLというrepeat-mapを定義する。
キーは(KEY . DEF)という形式のコンスセルを要素とする、
PAIRSリストによって継承する。ここでKEYDEF`define-key'
与えられるようにいくつかの要件を満たしていなければならない。
  `(progn
     (defvar ,symbol
       (let ((map (make-sparse-keymap)))
         (--each ,pairs (define-key map (car it) (cdr it)))
         map)
       ,docstring)
     ;; Teキーにrepeatマップ内であることを伝える。
     (--each (mapcar 'cdr (cdr ,symbol))
       (put it 'repeat-map ',symbol))))
       

以下のように使っている

(defrepeatmap window-repeat-map
  '(("}" . enlarge-window-horizontally)
    ("{" . shrink-window-horizontally )
    ("+" . balance-windows            )
    ("o" . other-window               )
    ("1" . delete-other-windows       )
    ("2" . split-window-below         )
    ("3" . split-window-right         )
    ("0" . delete-window              )
    ("s" . window-swap-states         )
    ("f" . project-find-file          ))
  "ウィンドウのキーシーケンス用のrepeatキーマップ。`repeat-mode'で使用")

u/oantolin

🔗

Votes 8

コツでもトリックでもないので&c.の話題だろうか。マニュアルのInit Fileセクションにはユーザーのメールアドレスを設定する例が記載されている:

(setq user-mail-address "cheney@torture.gov")

u/jcubic

🔗

Votes 8

わたしは大きなファイルを扱う際によく使用している。ファイル内部には、その位置にジャンプするために9箇所のブックマークを配置できるのだ。制限事項としてはブックマークに何かを追加すると場所がシフトされてしまうことだが、正しい位置を見つけるのは難しくないと思う。

これはC-c 0でブックマーク作成、C-c <1-9>でブックマークにジャンプするといった使い方をする。これは昔のブログにも記述している。しかし依然としてときどき使っている小技だ。

Emacsで高速にバッファーをブックマークする

u/WorldsEndless

🔗

Votes 8

イベントスケジュールにたいして素晴らしい計算機能を提供してくれるのが、org-evaluate-time-range (C-c C-y)だ。特定の長さをもったイベントをスケジュールする必要があるときには、2つの日付の間隔を正しく求めるために使用している。

u/viz_

🔗

Votes 8

一部の人にとってはこれが役に立つのは証明済みかもしれない。それはxdragonだ。

(defun vz/dired-popup-xdragon ()
  "マークしたファイルかポイント位置のファイルをxdragonでオープンする"
  (interactive)
  ;; xdragonのリネームがnixにまつわる事項だということは確実だ
  (make-process
   :name "xdragon"
   :command (append '("xdragon") (dired-get-marked-files))
   :noquery t))

ドラッグアンドドロップのサポートを探したとき、何かをドラッグする能力についてEmacsからは何も手掛かりを得られなかったので、(x)dragonを使ったという訳だ

u/spinochet

🔗

Votes 8

わたしは常々さまざまなバッファーのバックグラウンドカラーを色分けして、混み合ったスクリーンでバッファーを見つけやすいようにしたり、キーバインディングの違い(たとえばview-modeではSPCバーでページ繰り)を視覚的に把握できるようにしたいと思っていた。最終的には達成できたが、思ったより難しくなかった。

(defun bespoke-background-color ()
  "バッファーのタイプに応じてバックグラウンドを色分け"
  ;; after-change-major-mode-hookとview-mode-hookで呼び出す
  (cond
   ((member (buffer-name)
            (list "*Backtrace*" "*Compile-Log*"
                  "*Completions*" "*Messages*"))
    (buffer-face-set :background "#1f1d1b"))  ; brown
   ((member (buffer-name)
            (list "*Colors*" "*Faces*")) nil) ; text gray (8)
   ((derived-mode-p 'special-mode)
    (buffer-face-set :background "#1c221c"))  ; green
   ((or buffer-read-only view-mode)
    (buffer-face-set :background "#111c22"))  ; blue
   ((derived-mode-p 'prog-mode)
    (buffer-face-set :background "gray5"))    ; prog gray (5)
   (t nil)))                                  ; text gray (8)

u/meedstrom

🔗

Votes 8

しばらくdefrepeaterパッケージを使っていたが、こんなにエレガントに使えるものとは気づいていなかった!

(global-set-key [remap transpose-lines] (defrepeater #'transpose-lines))

実際には似たようなことがREADMEに記載されているようだが、読み飛ばしてしまったらしい。

u/khourhin

🔗

Votes 8

'desktop-environment-mode'がマジで役に立つこと、特にEXWMを使っていて標準的なファンクションキーに戻したいときには便利なことに気づいたのだ:
https://github.com/DamienCassou/desktop-environment

Damien、サンキュ!

u/ScottWC2

🔗

Votes 8

r/planetemacsがプライベートになった理由、誰か知ってる? プライベートなsubredditってRSS効かないので、気づいたのは4/15だよ。

u/b3n

🔗

Votes 8

わたしはEXWMモードを使っているので、Firefoxのような標準アプリケーションでEmacsの素晴らしいウィンドウ管理機能を普遍的に使用できている。

Firefoxのような現代的なブラウザのほとんどはタブをサポートしている。しかしタブはEmacsのビルトインのバッファー管理と比較すると大きく劣っている。さらにわたしは抽象化はアプリケーションレベルではなく、すべてのアプリケーションで利用できるように全般的なものを実装するべきだと考えている。多数のウェブブラウザの効果的な管理にウィンドウマネージャーが失敗するようになって、タブの重要度は増していくのではなかろうか。

わたしはタブバーを非表示にしてFireFoxを使っており、毎回新たなタブをオープンする拡張は、自動的に新たなウィンドウに新たなタブをオープンするようになっている。これで通常のようにバッファー切り替えコマンドを使って、息をするが如く100を超えるFireFoxウィンドウ'を扱うことができている。バッファー管理を改善するような何かを追加すれば、それはFireFoxにも自動で適用されるのだ。たとえば何日かvisitしていない古いバッファーをクリーンアップするために、最近"midnight-mode"を有効にしたが、これはFireFoxにも自動的に適用される(一度オープンしたウェブページを手作業で閉じるのは苦手だ)。

わたしの小技とトリックを説明しよう。わたしはFireFoxのウィンドウそれぞれにたいして、ファイル名としてURLをibufferに表示してもらいたいのだ。そうすればウィンドウ名、URLを個別に保持したまま、それらで検索を行うことができるからだ。ファイル名なら空なので、URLをセットするのに相応しいという訳だ。

FireFoxのタイトルにカレントURLを追加する拡張として、わたしはこれを使っているが、他の拡張でも機能すると思う。それから以下の関数を記述した:

(defun b3n-exwm-set-buffer-name ()
  (if (and exwm-title (string-match "\\`http[^ ]+" exwm-title))
    (let ((url (match-string 0 exwm-title)))
      (setq-local buffer-file-name url)
      (setq-local exwm-title (replace-regexp-in-string
                              (concat (regexp-quote url) " - ")
                              ""
                              exwm-title))))

  (setq-local exwm-title
              (concat
               exwm-class-name
               "<"
               (if (<= (length exwm-title) 50)
                   exwm-title
                 (concat (substring exwm-title 0 50) "…"))
               ">"))

  (exwm-workspace-rename-buffer exwm-title))

それからこの関数をexwm-update-class-hookexwm-update-title-hookという、2つのフックに追加した。

これでibufferでの表示は以下のようになった:

Firefox<Weekly tips/trick/etc/ thread : emacs — Mozilla Fi…>
https://www.reddit.com/r/emacs/comments/mb8u1m/weekly_tipstricketc_thread/

バッファー名は左、右はファイル名(かURL)、完璧だ :)

今後さらにC-x 3でウィンドウを分割してカレントウィンドウを複製するような改善を予定している。そうすれば通常のEmacsバッファーと同じように、同一ページの異なる位置にスクロールすることもできるからだ。EXWMでもシミュレーションキーで簡単に実現できる筈だ。

u/AffectionateAd8985

🔗

Votes 8

eshellcd =xxxは、zoxidez xxxのように、パターンxxxにマッチングする最近のディレクトリーにジャンプする。

u/desquared

🔗

Votes 8

orgモードで任意のツールチップをうまく使う方法についてしばらく考えていた。とても簡単な方法が見つかった: 存在しないリンクタイプを使うだけでよいのだ。

リンクのフォローやエクスポートについては関心がない。その場help-echoエリアにツールチップを表示するだけなので、次のようにすれば

[[abbrev:これはSome Random Acronymの略だ][SRA]]

orgリンクとして"SRA"を表示するバッファーでは、その上にマウスを移動すれば期待するメッセージが得られる。"abbrev"に特別な仕掛けはない、ただしorgリンクタイプとして定義されている点を除けばだが。このリンクを辿ろうとするとorgがヘディングの作成を試みるが、そのリンクを辿ったりエクスポートのような挙動は気にしない。

他にもフットノートのようなこと、たとえばテーブルのセルにある種のメモやコメントを追加したいが、セルが巨大化するのはよろしくないような場合だ。これは以下のようにテーブルを作成すればいいだろう:

|  列A  | メモ  |
|-------+-------|
|  1234 | [[whatever: これはテーブルのこの行に関するメモやコメント][note]]  |
|       |       |

セルには"メモ"としか記されていないが、マウスをホバーさせれば残りは確認できるだろう。

help-echoエリアに表示するリンクターゲット(メモ、略語、…)を得るには、help-at-pt-display-when-idleに適切な値をセットする必要があるだろう。https://emacs.stackexchange.com/questions/54319/how-to-display-target-of-an-org-mode-link-in-the-echo-area-or-as-tooltipを参照のこと。

u/kickingvegas1

🔗

Votes 8

Embedded calc mode: バッファーに清書していない計算を手っ取り早くバッファーに挿入する:

Embeddedモードに遷移するにはEmacsポイント(カーソル)を任意のバッファー内の式に配置してから、C-x * e
(calc-embedded)を押下するのだ。C-x * eはほとんどのCalxコマンドが使用するCalcスタックバッファーでは使用せず、独自にファイルをvisitしている通常の編集バッファーで使用することに注意。

u/nicholashubbard

🔗

Votes 8

以下はperspective.elにたいするconsultソースだ

(defvar consult--source-perspective
    `(:name "Perspective"
            :narrow   ?p
            :category buffer
            :face     consult-buffer
            :history  buffer-name-history
            :state    ,#'consult--buffer-state
            :default  t
            :items    ,#'persp-get-buffer-names)
    "`consult-buffer'用のPerspectiveの候補ソース")

u/[あぼーん]

🔗

Votes 8

(setq visual-order-cursor-movement t)

非nilなら矢印キーでのカーソル移動はvisual順にしたがう。

非nilなら文字を取り囲む双方向コンテキストに関わらずはディスプレイ上のポイントの右、なら左にポイントを任意のバッファー位置に移動できる。

テキストが全体的に左から右に記述されているときには、ロジカル順と視覚順両方でのカーソル移動が生成する結果は等しくなるだろう。

わたしが通常記述に使っているのはアラビア語なのだ。

u/elimik31

🔗

Votes 8

TeXLiveが提供するCLIプログラムtexdocは、LaTeXパッケージの名前を引数としてそのパッケージのドキュメントをオープンする(ドキュメントはローカルにインストールされている必要がある)。これはTeX-documentation-texdoc経由でAUCTeXからも利用できるので便利だ。しかしパッケージ名を手入力する必要がある(デフォルトでsymbol-at-pointを使用するにも関わらず)。しかし最近texdocのwikiでtab-completion,を追加するスニペットを見つけた。これにはインストール済みのTeXLiveパッケージ名のリストを入手する方法が示されていた。これをemacs
lispに移植した。completing-readcall-processを組み合わせて、インタラクティブな候補選択付きで自作のmy-texdocという端末コマンドを呼び出すのだ。Githubのgistで利用できるが、コードも貼り付けておこう:

(defun my-texdoc--get-package-list ()
  (let ((tlpdb-fpath (file-name-concat
                      (string-trim-right
                       (shell-command-to-string "kpsewhich -var-value TEXMFROOT"))
                      "tlpkg/texlive.tlpdb"))
        (name-regex "^name \\([^ \n.]+\\)$"))
    (with-current-buffer (find-file-noselect tlpdb-fpath 'nowarn 'rawfile)
      (save-excursion
        (goto-char (point-min))
        (cl-loop
         while (re-search-forward name-regex nil 'noerror)
         collect (match-string-no-properties 1))))))
    
(defun my-texdoc (pkg)
  "パッケージPKGのTeXドキュメントを表示する
インタラクティブに呼び出すとインタラクティブな補完付きで
TexLiveのパッケージを選択できる"
  (interactive
   (list (completing-read
          "texdoc: "
          (my-texdoc--get-package-list)
          nil nil nil
          'my-texdoc-history)))
    (call-process "texdoc" nil " *texdoc*" nil "--view" pkg))

一番問題なのが、これをEmacsコミュニティとどのように共有すればよいかわたしに確信がもてない点だ。独自パッケージとするほど大げさではないように思えるので、どこかのWikiやconsultのような集約的なパッケージに投稿することも考えたが、まずこのredditのスレッドに投稿しようと思う。AUCTeXとのマージに取り組むことも考えたが最早アクティブに開発されていないように見えたし、TeX-documentation-texdocソースコードはわたしのコードに比べて非常に複雑なので、何かを壊してしまうことも懸念している。

この投稿を本当に役に立つヒントとするために:
何かCLIプログラムがありそのプログラムで利用できる何らかの引数リストを得たいのなら、completing-readサポートを備えた独自のラッパーとなるemacs
lispコマンドを記述してみると良いだろう。楽しいし、それほど難しくもない。

u/ImJustPassinBy

🔗

Votes 8

confirm-kill-emacsという変数を見つけた。auctexで頻繁に使用する関数がC-c C-v (C-x C-cから1つ離れたキー)にバインドされたせいで、誤ってEmacsを終了してしまうこともなくなるだろう。

u/snippins1987

🔗

Votes 8

コンテキスト:
ついにorg-mode(特にorg-rome)に手を出して多くのelispを記述したが、org-modeによって提供される洗練された他のエクスペリエンスと比較すると、
org-tabletable.el
の扱いについては場違いでぎこちなく、未だに満足していない。諦めて基本的にはスプレッドシートファイルをorgファイルにリンクすることにした。

これが理想的でないことは明らかだ。わたしはlibreofficeのcalcとは別にテーブルを閲覧する必要があるからである。そしてノートをGitLabやGitHub等で閲覧することはできない。

そこでorgノート内部にスプレッドシートを描画するためにorg-babelの力を借りることにした。

これを行うためにわたしはssconvert、ImageMagick、Firefoxを使用するemacs_excel_to_pngというbashスクリプトを作成した。このスクリプトはスプレッドシートをhtmlに変換してFirefoxで描画、最後に描画したイメージからの切り取りにImageMagickを使用する。このスクリプトはorgリンクをプリントするので、イメージは結果セクションに表示される。

これによりorgファイルで以下のようなことを行うことができる:

#+begin_src bash :dir ./ :results raw :var ZOOM=1.3
export ZOOM; emacs_excel_to_png \
    "note_files/emacs_excel_to_png.xlsx" \
    "note_files/emacs_excel_to_png.png"

\#+END\_SRC

emacs_excel_to_pngスクリプトの内容は以下のとおり:

#!/usr/bin/env bash
    
```bash
excel_file="$1" output_file="$2"
    
if [[ "$#" -lt 2 ]]; then
    notify-send "Not enough parameters"
    exit
fi
    
tmp_dir="/dev/shm" mkdir -p $tmp_dir/emacs_excel_to_png
    
if ! [[ "$excel_file" = /* ]]; then
    excel_file="${PWD}/${excel_file}"
fi
    
if ! [[ "$output_file" = /* ]]; then
    output_file="${PWD}/${output_file}"
fi
    
if [[ -z "$ZOOM" ]]; then
    ZOOM="1.3"
fi
    
cd $tmp_dir/emacs_excel_to_png || exit
    
# xlsxをhtmlに変換
ssconvert --export-type=Gnumeric_html:html40
--import-type=Gnumeric_Excel:xlsx "$excel_file"
"$tmp_dir/emacs_excel_to_png/output.html" 2> /dev/null
    
# 1シートだけなら出力HTMLからシートのキャプションを削除する
n_sheets=$(grep -c "<caption>" $tmp_dir/emacs_excel_to_png/output.html)
if [[ "$n_sheets" -eq "1" ]]; then
    sed -i '/<caption>/d' $tmp_dir/emacs_excel_to_png/output.html
fi
    
# 環境変数ZOOMを使ってテーブルのスケーリングを行う
sed -i "s/<\/style>/body { transform-origin: top left; transform:
scale(${ZOOM}, ${ZOOM}); }<\/style>/g"
$tmp_dir/emacs_excel_to_png/output.html
    
# HTMLからPNGへの変換にはfirefoxのスクリーンショット機能を使用する
# Note: -P screenshotではスクショ取得に別プロファイルを作成する必要がある
# firefoxが既に実行中というエラーは発生しない
/usr/bin/firefox -P screenshot --headless --window-size 3840 --screenshot
file://$tmp_dir/emacs_excel_to_png/output.html > /dev/null 2>&1
    
# データ領域だけを残してイメージはトリミングしてカラー反転する
convert -trim -negate screenshot.png screenshot.trimmed.png 2> /dev/null
    
# 結果イメージを適切な場所に移動する
mv screenshot.trimmed.png "$output_file"
    
# 出力をorg-modピクチャーリンクとしてプリントアウト
echo "[[file:${output_file}]]"
    
# クリーンアップ
rm -rf $tmp_dir/emacs_excel_to_png

u/Sudo_Brew

🔗

Votes 8

comment-lineがポイントを1行下に移動したり、どういう訳かたまに非アクティブなリージョンをコメントアウトする挙動に悩まされていた。行末にコメントを追加する際のcomment-dwimのsingle-lineの挙動も気に食わない。わたしはリージョンがアクティブならそのリージョンのcomment/uncomment、そうでなければポイント位置のcomment/uncommentにしたかったので、以下のように高速で簡単な関数を記述した。

(defun my/comment-dwim ()
  "リージョンがアクティブならリージョン、それ以外は行をコメントアウトする

これにより`comment-line'の過剰なコメント、
`comment-dwim'の奇妙な1行コメントを回避できる"
  (interactive)
  (save-excursion
    (if (use-region-p)
        (call-interactively #'comment-or-uncomment-region)
      (call-interactively #'comment-line))))

u/nicholashubbard

🔗

Votes 8

この関数はカレントの入力行を保ちつつDwim方式でcomint-modeのバッファーをクリアーする。そしてカーソルが入力行の上にある際にも機能する。わたしはshell-modeとielmでC-lにバインドしているが、とても快適に機能する。

(defun my/comint-clear ()
  (interactive)
  (let ((orig-ln (line-number-at-pos))
        (col (current-column))
        (cmd (progn (end-of-buffer)
                    (move-end-of-line nil)
                    (set-mark (point))
                    (move-beginning-of-line nil)
                    (buffer-substring (region-beginning) (region-end))))
        (after-ln (line-number-at-pos)))
    (delete-region (region-beginning) (region-end))
    (comint-clear-buffer)
    (insert cmd)
    (if (= orig-ln after-ln)
        (move-to-column col t)
      (move-beginning-of-line nil))))

u/ImJustPassinBy

🔗

Votes 8

LaTeXユーザー向けの謳い文句:
bibtool.bibファイルをクリーンアップするソフトウェアであり、ほとんどのtexディストリビューションに含まれている。これは参考文献(bibliography)のソート、レイアウトの標準化、系統的なキーの生成さえ可能だ。これは以下のように実行できる:

bibtool input.bib -o output.bib

(デフォルトの出力は見栄えがあまりよろしくないが、最小限のコンフィグは以下を参照して欲しい)

For LaTeX+Emacsユーザー向け:
以下はカレントバッファーでbibtoolを実行する小さな関数だ:

(defun my/bibtool-current-file ()
  "カレントバッファーのファイルにbibtoolを実行する"
  (interactive)
  (let ((file (buffer-file-name)))
    (if file
        (let ((default-directory (file-name-directory file))
              (base-file (file-name-nondirectory file)))
          (shell-command (concat "bibtool " base-file " -o " base-file)))
    (message "Not visiting a file!"))))

そして以下はbibtool用の最小限のコンフィグだ。bibtoolを呼び出すフォルダやホームフォルダに.bibtoolrscという名前で保存すればよいだろう:

sort = on sort.format = {%N(author)}

sort.order{* =
    author
    bibkey
    title
    editor
    booktitle
    mrnumber
    zbl
    journal
    fjournal
    series
    volume
    number
    note
    howpublished
    address
    organization
    publisher
    edition
    pages
    year
    month
    doi
    url
}

print.align.key = 0
print.line.length = 120
preserve.key.case = on
sort.cased = off
print.use.tab = off

fmt.name.name = { }
fmt.inter.name = { x }

u/pjhuxford

🔗

Votes 8

*Help*バッファーででhelp-view-sourceを実行(またはsを押下)すると、カレントのヘルプアイテムのソースにジャンプできる。しかしデフォルトではこれはhelpバッファーとは別のバッファーにソースをオープンするだろう。

しかし*Help*バッファーのウィンドウをソースバッファーのウィンドウに置き換える方が、個人的には直感的だということに気づいた。これはEmacs
29+ではユーザーオプションhelp-window-keep-selectedに非nil値をセットすれば実現できるのだ。更にhelpバッファーでhelp-goto-infoを実行(あるいはiを押下)すれば*Help*の再利用ができる。

Emacs 30+を読むと、更に新たなコマンドhelp-find-source (グローバルにC-h 4 sにバインドされている)を発見した。*Help*バッファーが存在(選択されたウィンドウである必要はない)する場合には、カレントウィンドウで*Help*バッファーに応じたソースファイル(もしあれば)にジャンプするのだ。

u/mindgitrwx

🔗

Votes 8

このスレッドは通常なら定期的に更新されるという訳ではないの?

u/80286

🔗

Votes 8

最近historyというパッケージに関する小さな議論を見つけた。

Emacsのナビゲーションには常に複数の手段がある。たとえばxrefやimenu、infoページでのノード切り替えといった具合だ。行ったすべてのナビゲーションにたいしてグローバルにバックや前進する統合的手段に言及しないのはどうしてだろう。

以前いた場所、たとえば4回前のナビゲーションステップに戻りたいのだが、特定の場所で行ったナビゲーションステップそれぞれにおける"戻る"には、精神的なコンテキストスイッチが伴うというのが頭痛のタネだ。

ブラウザの戻る/進むボタンのように機能させるための何らかが欠けているのだ。その機能とは特定のタブで訪れた任意のサイトであればナビゲートしている特定のサイトの外部にあるウェブページであってもナビゲートできるという機能だが、これはEmacsの機能ごとのヒストリーの動作に似たところがある。戻る/進むボタンが常に正確に機能する訳ではないが、複雑なウェブサイトが存在するかぎり未だに必要な機能だ。

dgutovのEmacsコンフィグを読んで、既存パッケージを使用してこれをこれを効果的に実現できること、dgutovの素晴らしい基本的なセットアップを発見した。

ついに数日前にEmacsに欠落していたわたしの使用パターンを実現する、"グローバル"なヒストリーを得ることができた。
So, for the last few days I have finally the "global" history that emacs has
been lacking in my pattern of use.
これは結局のところ複雑な問題なので問題も発生するだろうが、今までのところはうまく機能している。

わたし個人のセットアップ::

(use-package history
    :ensure t
    :bind (
         ("M-8" . #'history-prev-history)
         ("M-9" . #'history-next-history)
         ("M-0" . #'history-add-history))        
    :config
    ;package original: (imenu isearch-mode beginning-of-buffer end-of-buffer)    
    (setq history-advised-before-functions 
          '(isearch-mode 
            find-function-do-it 
            find-library
            imenu beginning-of-buffer 
            end-of-buffer
            xref-find-definitions 
            counsel-imenu counsel-git-grep
            xref-find-references
            paredit-backward-up 
            backward-up-list
            ;; may be risky
            switch-to-buffer
            ))
    (history-mode +1)
    )
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?