Editörde Kullandığım Eklentiler

May 15, 2020 7 dakika

VSCode benim sevdiğim ve takip ettiğim bir editör; ancak alışkanlıkları değiştirmek zor olduğu için Emacs kullanmaya devam ediyorum. Başta VSCode olmak üzere, farklı editörler için yazılmış çeşitli blog yazılarından ilham alarak arada yapılandırma dosyamı güncelliyorum. Ben de bu yazıyla Emacs üzerinden, kullandığınız editör için ilham verebilmeyi ümit ediyorum. Yazıda bahsettiğim yapılandırmaların tümüne bu repodan erişebilirsiniz.

Tema, Font ve Arayüz Bileşenleri Hakkında Ön Bilgi

Yazının ilerleyen bölümlerinde kullanacağım bazı terimlerin iyi anlaşılabilmesi için, arayüz hakkında küçük bir bilgi vermeliyim. Emacs’in grafik arayüzü birkaç ana bileşenden oluşmaktadır:

  1. Frame: Masaüstü ortamımızın penceresi, Emacs için çerçeve olarak adlandırılır. Emacs’i bir kere çalıştırıp, birden fazla çerçeve açabiliriz. Bir sunucuda Emacs’i servis gibi çalıştırıp, birden fazla geliştirici o servise bağlanıp kendi çerçevelerinde kodlama yapabilirler. Live Share kadar pratik olmasa da benzer işlevi görür.

  2. Window: Her çerçeve en az bir pencere barındırır ve birden fazla da olabilir. Her pencere bir buffer’i gösterir.

  3. Buffer: Pencerelerin içinde gösterilen dosya, pdf, resim, yardım sayfası, mesaj, terminal emülatörü, mail uygulaması, hatta bir web sayfası buffer olarak adlandırılır. İki taraflı bilgi alışverişinin olduğu bir tampon bölgedir.

  4. Mode line: Pencerelerin altında yer alan, buffer ile ilgili dosya adı, çalışan modlar, imleç pozisyonu, aktif git branşı gibi bilgileri gösteren satırdır.

  5. Mini buffer: Mode line’ın da altında yer alan, autocomplete’in çalıştığı, arama sonuçlarının veya geçici logların gösterildiği küçük bir alandır.

  6. Fringe: Pencerelerin yan kenarlarında bulunan ince boşluk, kenarlıktır. Burada test coverage bilgisi, git diff çıktısı, yer imleri, imleç pozisyonu, kod hataları gibi satırla ilgili bilgi gösteren renk, ikon veya karakterler yer alır.

Bunun dışında, tepede header line, toolbar, menu gibi bileşenler bulunmaktadır. Bir de Emacs 27 sürümüyle birlikte tab bar mode geleceğini öğrendim. Bunları ben kullanmıyorum.

Tema seçerken, eklentileri ne kadar göz önünde bulunduruyor, ne kadar özelleştirilebilir ve ne kadar erişilebilirliğe uygun, bunlara dikkat ediyorum. Ben Operandi ve Vivendi adıyla iki çeşidi olan Modus temasını kullanıyorum.

Font olarak uzun süre Fira Code kullandım ve hala Terminal uygulamalarında kullanmaya devam ediyorum. Şimdi ise italik fontlarını çok beğendiğim için IBM Plex Mono kullanıyorum. Malesef font ligatures desteği tam olarak yok.

Sürüm Kontrol Sistemi

Artık Git dışında bir sürüm kontrol sistemi kullanan kaldı mı, bilmiyorum. Bitbucket bile yeni kod deposu oluştururken, “Mercurial mı, yoksa Git mi?” diye sormayı bıraktı. Dolayısıyla sadece git eklentileri kullanıyorum. Bunlardan birincisi tabi ki Magit! O kadar güzel bir şey ki Magit, Emacs’e bulaşmadan bağımsız bir uygulamaymış gibi kullanabilmek için docker container imajı bile var. Tabi yine kısayollarına hakim olmak gerekiyor.

Bunun dışında, satır değişikliklerini takip etmek için diff-hl adında bir fringe eklentisi kullanıyorum.

(use-package diff-hl
  :config
  (global-diff-hl-mode)
  (if (not (display-graphic-p))
      (diff-hl-margin-mode)))

Arama, Filtreleme Eklentileri

Uzun bir süre git grep ve silversearcher kullandım. Şimdi sadece ripgrep kullanıyorum. Neden? En rahat bunun kaynak kodunu okuyabildiğim için. Yoksa diğerlerinden çok bir artısı olduğunu sanmıyorum.

Tabi arama sonuçlarını mini buffer üzerinden görebilmek için swiper kullanıyorum. Bu eklenti sadece kod aramada değil, komut veya buffer filtrelerken de kolaylık sağlıyor.

(use-package swiper
  :bind (("C-s" . swiper)))

(use-package counsel
  :bind (("M-x"     . counsel-M-x)
         ("C-r"     . counsel-rg)
         ("C-x C-f" . counsel-find-file)
         ("C-x C-d" . counsel-git)))

Bazen klavye makrolarını akılda tutmak, öğrenmek zor oluyor. Bunun için de which-key ve hydra kullanıyorum. Böylece makrolar için kopya kağıtları hazırlayabiliyorsunuz.

(use-package which-key
  :config
  (which-key-mode)
  :diminish)

(use-package hydra
  :bind (("C-c e" . hydra-errors/body))
  :config
  (defhydra hydra-errors (:pre (flycheck-list-errors)
                               :post (quit-windows-on "*Flycheck errors*")
                               :hint nil)
    "Errors"
    ("f"   flycheck-error-list-set-filter      "Filter")
    ("j"   flycheck-next-error                 "Next")
    ("k"   flycheck-previous-error             "Previous")
    ("RET" nil                                 "Close" :color blue)))

İmleç Gezdirme (Navigation)

Emacs, Vim gibi editörlerde kodda gezinirken mouse ve yön tuşlarına ne kadar az ihtiyaç duyulursa o kadar hız kazanırsınız. Örneğin avy ile aktif bufferlar arasında nokta atışı bir harfe gidebilirsiniz. rainbow-delimiters ile parantez çiftlerini farklı renklendirip gitmek istediğiniz pozisyonu daha net görüp, imleci önceki ve sonrakine götürebilirsiniz. Belli bir kod blokunu seçmek, seçimi fonksiyon, metod veya class gibi bloklara genişletmek için expand-region kullanabilirsiniz.

Bazen yapılan değişiklikleri geri alıp, bir şeyler kopyaladıktan sonra tekrar ileri dönmek isteyebilirsiniz. Emacs’in varsayılan undo - redo mantığı epey yorucu oluyor benim için, bu nedenle undo-fu kullanmayı tercih ediyorum.

(use-package avy
  :bind (("M-g g" . avy-goto-char-2)
         ("M-g f" . avy-goto-char))
  :config
  (avy-setup-default))

(use-package expand-region
  :bind (("C-M-w" . er/expand-region))
  :defer t)

(use-package rainbow-delimiters-mode
  :ensure rainbow-delimiters
  :hook prog-mode)

(use-package undo-fu
  :bind (("C-z" . undo-fu-only-undo)
         ("C-M-z" . undo-fu-only-redo))
  :defer t)

Bunun dışında diff-hl ile kod değişikliğinin olduğu satırlarda gezinmek, flycheck ile hata veren satırlara göz atmak kolaylaşıyor. Makroları CTRL (Control) ve Alt (Option) tuşları üzerinden gruplayarak yön tuşlarını daha işlevsel kullanmak mümkün olabilir. Örneğin CTRL tuşuyla imleci tek karakter hareket ettirirken, Alt tuşunu kullanırken imleci bir sonraki - önceki - yukarıdaki - aşağıdaki boşluğa götürebilirsiniz. Bunu Emacs’te kendiniz yapılandırmanız gerekiyor, bir örneğini aşağıda bulabilirsiniz:

(global-set-key (kbd "M-p") 'backward-paragraph)
(global-set-key (kbd "M-n") 'forward-paragraph)

Pencere Yönetimi

Emacs’te tab gösterimi 27 sürümüyle gelecek, geldiğinde kullanır mıyım, emin değilim. Belki tabları masaüstünde çalışan veya pinlenmiş programların yer aldığı task bar gibi kullanmayı düşünebilirim. Aslında Emacs’i, i3wm gibi tiling window manager gibi düşünebilirsiniz. İstediğiniz kadar birbirine döşenmiş pencereler oluşturup boyutlandırabiliyor, bu pencerelerin içinde dosyalar veya uygulamalar açıp düzenleyebiliyorsunuz. Yalın haldeyken pencere geçişlerini yönetmek biraz zor olabiliyor. Bunun için birkaç güzel eklenti var.

Bunlardan ilki ace-window. Tüm çerçevelerde yer alan pencereler arası geçiş yapmak, yeni bir pencereyi belli bir buffer ile açmak, aktif olmayan diğer pencereleri kapatmak, yatay veya dikey bölmek ya da birleştirmek, pencereleri değiş tokuş yapmak gibi yetenekleri var.

(use-package ace-window
  :config
  (custom-set-faces
   '(aw-leading-char-face ((t (:height 1.0)))))
  :defer t
  :diminish
  :init
  (global-set-key (kbd "M-o") 'ace-window)
  (setq aw-background nil)
  (setq aw-dispatch-always t))

İkincisi eyebrowse. Bazen pencere düzeninizi bozmak istemezsiniz, yeni bir projeye geçip orada farklı dosyaları açıp ve projeler arasında geçiş yapmak isteyebilirsiniz. Bazen üçüncü parti bir kütüphanenin kaynak kodlarına bakmak istersiniz, onun dosyalarını, kendi projenizin dosyalarıyla karıştırmak istemezsiniz. Bir nevi, Windows’ta taskbar’a kavuşmuş oluyorsunuz.

(use-package eyebrowse
  :init
  (eyebrowse-mode t))

Üçüncüsü zoom. Bu eklenti sayesinde artık pencere boyutlandırma diye bir ihtiyacım kalmadı. Hangi pencerede çalışıyorsam, onun kapsam alanını genişletip, diğerlerini daraltıyor. Çerçeveleri dikey birkaç pencereye bölüp pencereler arasında geçiş yaptığınızda sanki kitaptan sayfa çeviriyormuşsunuz gibi oluyor. Algoritması biraz karışık çünkü çerçeve boyutuna göre pencereleri hesaplamaya çalışıyor ve bazı çözünürlüklerde bu algoritmaya müdahale etmek gerekebiliyor.

(use-package zoom
  :diminish
  :config
  (zoom-mode t)
  (setq zoom-size '(0.618 . 0.618)
	zoom-ignored-major-modes '(which-key-mode
                                   hydra-mode)))

Son olarak frog-jump-buffer eklentisinden bahsetmeliyim. Bazen açmak istediğiniz dosyanın adını unutur, hepsine bir göz atmak istersiniz. Emacs’te zaten bunun için bir çözüm var ama bu da güzel bir alternatif olarak tavsiye edilir.

(use-package frog-jump-buffer
  :bind (("C-x C-b" . frog-jump-buffer))
  :defer t)

Kod Tamamlama, Denetleme ve Düzenleme

Microsoft’un VSCode ile birlikte geliştiricilere sağlamış olduğu en güzel şey nedir sorarsanız, herhalde LSP ve DAP derim. Yazıyı bu iki güzel eklentiyle uzatmak istemiyorum ama hangi editör kullanıyorsanız kullanın, bir göz atıp bakmanızda fayda olduğunu düşünüyorum. lsp-mode ile kod tamamlama, imleci belli bir değişken, sınıf, fonksiyon veya değerin tanımlandığı yere götürmek, referansların listesini elde etmek, kodu refactor etmek, satır içi kod standartları veya derleme hataları ile ilgili bilgiye erişmek, dökümantasyona ulaşmak gibi bir sürü yeteneği var. Ayrıca dap-mode ile kodu editör üzerinden çalıştırıp debug etme imkanınız oluyor.

(use-package lsp-mode
  :commands (lsp lsp-deferred)
  :diminish
  :hook ((css-mode        . lsp-deferred)
         (dart-mode       . lsp-deferred)
         (go-mode         . lsp-deferred)
         (javascript-mode . lsp-deferred)
         (python-mode     . lsp-deferred)
         (rust-mode       . lsp-deferred)
         (web-mode        . lsp-deferred)
         (yaml-mode       . lsp-deferred)
         (lsp-mode        . lsp-enable-which-key-integration))
  :init
  (setq
   lsp-keymap-prefix "C-c l"
   lsp-prefer-capf t
   lsp-idle-delay 0.500
   lsp-enable-snippet nil
   lsp-signature-doc-lines 10
   lsp-signature-auto-activate nil))

Tabi bunları yapabilmek için de pek çok eklentiye de ihtiyaç duyuluyor. LSP Mode zaten bunları yüklüyor ve varsayılan bir ayarı var. Ama bazı tercihleriniz farklı olabilir. Örneğin ben sözdizimi kontrolü için flymake yerine flycheck, kod tamamlama önerilerinin gösterileceği popup için company tercih ediyorum.

(use-package flycheck
  :diminish
  :init
  (global-flycheck-mode))

(use-package flycheck-rust
  :config
  (add-hook 'flycheck-mode-hook #'flycheck-rust-setup))

(use-package company
  :bind ("C-c TAB" . company-complete-common)
  :config
  (push 'company-capf company-backends)
  :diminish
  :hook ((after-init . global-company-mode))
  :init
  (setq-default company-dabbrev-ignore-case t
                company-dabbrev-code-ignore-case t)
  (setq company-idle-delay 1
        company-minimum-prefix-length 2
        company-require-match 'never
        company-show-numbers nil
        company-tooltip-align-annotations t
        company-tooltip-flip-when-above t
        company-tooltip-limit 10))

Bunun dışında parantez çiftlerini otomatik ekleyen smartparens, önceden tanımlı kod parçacıklarını kolayca yapıştırmak için yasnippet kullanıyorum.

(use-package yasnippet
  :config
  (yas-global-mode 1)
  :diminish (yas-minor-mode))

(use-package yasnippet-snippets
  :after yasnippet)

(use-package smartparens
  :diminish
  :config
  (require 'smartparens-config)
  (smartparens-global-mode t)
  (show-smartparens-global-mode t))

Son olarak

Bahsetmediğim çok eklenti var ama yazıyı uzatmak istemedim. Doğru eklentileri kullandığımızda editörlerden daha fazla verim alabiliyoruz. Editör savaşlarını her ne kadar işin goygoyunda olsak da gereksiz buluyorum. Bir dönem .NET için Visual Studio kullanırken afallamıştım; ama Twitch’te tüm marifetiyle, yüksek verimde kullanabilen insanları da gördüm.

Bu yazıyı yazmama vesile olan Berat Bozkurt‘a ayrıca teşekkürler.