Schede in stile browser per emacs?


22

Vorrei schede come Firefox, ma per Emacs.

Ho trovato questo: http://emacswiki.org/emacs/TabBarMode

Ma aggiunge a ciascun buffer ( finestra nella terminologia di Emacs) una barra che mostra i buffer attualmente aperti.

Vorrei che una scheda potesse contenere più buffer ( finestre nella teminologia di Emacs), che posso dividere a piacimento. Vale a dire ogni scheda dovrebbe corrispondere a uno "stato della finestra" (nel senso di window-state-get).

Avrei una scheda per i miei compiti, un'altra per il codice, un'altra per la lettura del web ecc.

È possibile? Tabbar può essere personalizzato per fare questo?

[edit2]
Questa domanda ha attirato più attenzione di quanto mi aspettassi. Sembra che ci sia una soluzione, ma che richiederebbe un po 'di ricerca e ottimizzazione. Mentre questa / la prossima settimana sono un po 'impegnate per me, analizzerò le risposte e proverò a costruire qualcosa che funzioni e poi modificherò questa domanda per riflettere i miei risultati. Ti preghiamo di tenere premuto =)

[modifica] Tipo
di simile a:
/programming/24157754/make-frames-in-emacs-gui-behaves-like-frames-in-terminal

Mi accontenterei di più frame anche in una singola sessione della GUI.


2
"Vorrei che una scheda potesse contenere più buffer, che posso dividere come desiderato." Intendi più finestre ?
Malabarba,

1
È più come mi piacerebbe avere schede molto dyanmic. Li creerei e poi li popolerei con Windows. Cioè vorrei una scheda per essere una cornice. Quindi una nuova scheda, una nuova cornice. All'interno di ogni scheda / cornice ho potuto aprire le finestre / (buffer) desiderati. È fattibile? (Vale a dire, nessun nome di buffer codificato, ecc.)
Leo Ufimtsev

1
C'è una variabile associata a finestre particolari, ma sono passati un mese o due da quando ho visto un thread che ne parlava e non so come si chiamasse fuori mano. Potresti essere interessato a utilizzare un sistema simile a frame-bufs in cui un elenco contiene i buffer associati a un frame e tale elenco è incorporato nel parametro frame. È possibile utilizzare la variabile associata a una determinata finestra e trasformarla in un elenco, aggiungere / rimuovere buffer dall'elenco: tale elenco sarebbe un gruppo di buffer da utilizzare con la barra delle schede. Tutto ciò è teorico, ma credo che funzionerebbe.
elenco delle leggi

1
Penso che potresti riferirti a: stackoverflow.com/questions/24157754/… ma quel post non sembra avere una risposta solida: - /
Leo Ufimtsev

1
Consiglierei di dare un'occhiata al pacchetto elscreen.
Blarghmatey,

Risposte:


8

Dividi i buffer in gruppi

È possibile con la barra delle schede. È possibile aggiungere regole per raggruppare i buffer in gruppi. Ecco uno snippet di base:

(defun tabbar-buffer-groups ()
  "Returns the list of group names the current buffer belongs to."
  (list
   (cond

    ;; ADD RULES TO SPLIT BUFFERS IN GROUPS HERE!

    ;; if buffer is not grouped by the rules you would add above 
    ;; put it in the "General" group:
    (t
       "General"
     ))))

Regole di esempio:

  1. Elenca i nomi dei buffer:
    ((member (buffer-name)
             '("*scratch*" "*Messages*" "*Help*"))
     "Common" ;; this is a group name
     )
  1. Per quanto riguarda i buffer comuni preferisco mettere in "Common" ogni buffer il cui nome inizia con una stella. Questo fornisce un esempio di creazione di un buffer per questa regola:
    ((string-equal "*" (substring (buffer-name) 0 1))
     "Common"
     )
  1. Ecco un esempio di raggruppamento di buffer per modalità principale:
    ((memq major-mode
           '(org-mode text-mode rst-mode))
     "Text"
     )
  1. Ecco un esempio di raggruppamento dei buffer in base alla modalità da cui derivano:
    ((or (get-buffer-process (current-buffer))
         ;; Check if the major mode derives from `comint-mode' or
         ;; `compilation-mode'.
         (tabbar-buffer-mode-derived-p
          major-mode '(comint-mode compilation-mode)))
     "Process"
     )
  1. Ecco un esempio di raggruppamento di schede per regexp:
    ((string-match "^__" (buffer-name))
     "Templates"
     )
  1. Raggruppa i buffer in base alla modalità principale:
    (if (and (stringp mode-name)
                  ;; Take care of preserving the match-data because this
                  ;; function is called when updating the header line.
                  (save-match-data (string-match "[^ ]" mode-name)))
             mode-name
           (symbol-name major-mode))

Dopo aver composto le regole, è possibile premere + o - nella scheda della barra delle schede per attivare / disattivare i gruppi, e anche ◀ e ▶ per passare da un buffer all'altro. O semplicemente associa i seguenti defuns:

tabbar-forward
tabbar-backward
tabbar-forward-group
tabbar-backward-group

e spostati tra le schede e i gruppi di schede con la tastiera.

Personalmente raggruppo le schede, in modo da vedere ciò che è aperto, ma navigo con ido-switch-buffer.

Passa da un set di regole a un altro

Inoltre, è possibile definire un diverso insieme di regole di raggruppamento del buffer e passare da una all'altra. Ecco un esempio di ciclo tra due serie di regole di raggruppamento del buffer:

;; tab-groups!
(setq tbbr-md "common")
(defun toggle-tabbar-mode ()
  "Toggles tabbar modes - all buffers vs. defined in the `tabbar-buffer-groups'."
  (interactive)
  (if (string= tbbr-md "groups")
      (progn ;; then
        (setq tabbar-buffer-groups-function 'tabbar-buffer-groups-common)
        (setq tbbr-md "common"))
    (progn ;; else
      (setq tabbar-buffer-groups-function 'tabbar-buffer-groups)
      (setq tbbr-md "groups"))))
;; by default - all tabs:
(setq tabbar-buffer-groups-function 'tabbar-buffer-groups-common)

In questo modo si alternano tabbar-buffer-groups-commone si tabbar-buffer-groupsraggruppano i defun.

Ordina i buffer della barra delle schede per nome

Trovo utile ordinare i buffer della barra delle schede per nome. Ecco come ottenerlo:

(defun tabbar-add-tab (tabset object &optional append_ignored)
  "Add to TABSET a tab with value OBJECT if there isn't one there yet.
If the tab is added, it is added at the beginning of the tab list,
unless the optional argument APPEND is non-nil, in which case it is
added at the end."
  (let ((tabs (tabbar-tabs tabset)))
    (if (tabbar-get-tab object tabset)
        tabs
      (let ((tab (tabbar-make-tab object tabset)))
        (tabbar-set-template tabset nil)
        (set tabset (sort (cons tab tabs)
                          (lambda (a b) (string< (buffer-name (car a)) (buffer-name (car b))))))))))

Grazie per la risposta dettagliata Proverò a provare quanto sopra e ti farò sapere ~ alla fine :)
Leo Ufimtsev,

Ma l'OP non vuole "una tabbar per finestra", vuole una tabbar per frame e ogni tab nella tabbar dovrebbe rappresentare una "finestra config" (cioè diverse finestre) piuttosto che un buffer, quindi raggruppare i buffer non è il problema .
Stefan

6

ATTRIBUTO: il raggruppamento di buffer in base al frame è un'implementazione diretta dei concetti e seleziona parti di codice sviluppate / scritte da Alp Aker nella libreria frame-bufs: https://github.com/alpaker/Frame-Bufs

Di seguito è riportato un esempio di come utilizzare la libreria tabbar.ele raggruppare le schede / i buffer in modo dinamico su una base per fotogramma aggiungendo schede / buffer con C-c C-ao rimuovendo schede / buffer con C-c C-n. Esistono solo due (2) gruppi - associati al frame corrente (cioè, "A") e NON associati al frame corrente (cioè, "N"). I gruppi sono frame-local, il che significa che ogni frame può avere il proprio raggruppamento. Il raggruppamento personalizzato può essere ripristinato con C-c C-r. Passa tra i gruppi associati e non associati con C-tab. Passa alla scheda / buffer successiva nel gruppo corrente con M-s-right. Passa alla scheda / buffer precedente nel gruppo corrente con M-s-left.

Le schede / i buffer possono essere aggiunti o rimossi in modo programmatico con my-add-buffere my-remove-buffer. Per un esempio di come aprire determinati buffer in frame selezionati, consultare il thread correlato intitolato Come intercettare un file prima che si apra e decidere quale frame : /programming//a/18371427/2112489 La funzione my-add-bufferdovrebbe essere incorporato nelle posizioni appropriate del codice nel collegamento sopra se un utente sceglie di implementare quella funzione.

L'utente potrebbe voler creare una voce in un'abitudine mode-line-formatche visualizzi il nome del gruppo di schede corrente nella riga della modalità incorporando il seguente frammento: La (:eval (when tabbar-mode (format "%s" (tabbar-current-tabset t)))) personalizzazione della riga della modalità in modo più dettagliato, tuttavia, non rientra nell'ambito di questo esempio.

La funzione tabbar-add-tabè stata modificata in modo da alfabetizzare le schede / i buffer.

La funzione tabbar-line-tabè stata modificata in modo da fornire quattro (4) facce diverse a seconda della situazione. Se la scheda / buffer è associata al frame e IS selezionata, utilizzare tabbar-selected-associatedface. Se la scheda / buffer è associata alla cornice e NON selezionata, utilizzare la tabbar-unselected-associatedfaccia. Se la scheda / buffer NON è associata al frame ed è selezionata, utilizzare la tabbar-selected-unassociatedfaccia. Se la scheda / buffer NON è associata alla cornice e NON è selezionata, utilizzare la tabbar-unselected-unassociatedfaccia.

;; Download tabbar version 2.0.1 by David Ponce:
;;   https://marmalade-repo.org/packages/tabbar
;; or use package-install for marmalade repositories.

;; Place tabbar-2.0.1.el in the `load-path` -- it is okay to rename it to tabbar.el
;; or add the directory (where `tabbar.el` resides) to the `load-path`.
;; EXAMPLE:  (setq load-path (append '("/Users/HOME/.emacs.d/lisp/") load-path))

(require 'tabbar)

(setq tabbar-cycle-scope 'tabs)

(remove-hook 'kill-buffer-hook 'tabbar-buffer-track-killed)

(defun my-buffer-groups ()
  "Function that gives the group names the current buffer belongs to.
It must return a list of group names, or nil if the buffer has no
group.  Notice that it is better that a buffer belongs to one group."
  (list
    (cond
      ((memq (current-buffer) (my-buffer-list (selected-frame)))
        "A")
      (t
        "N"))))

(setq tabbar-buffer-groups-function 'my-buffer-groups) ;; 'tabbar-buffer-groups

;; redefine tabbar-add-tab so that it alphabetizes / sorts the tabs
(defun tabbar-add-tab (tabset object &optional append)
  "Add to TABSET a tab with value OBJECT if there isn't one there yet.
If the tab is added, it is added at the beginning of the tab list,
unless the optional argument APPEND is non-nil, in which case it is
added at the end."
  (let ((tabs (tabbar-tabs tabset)))
    (if (tabbar-get-tab object tabset)
        tabs
      (let* ((tab (tabbar-make-tab object tabset))
             (tentative-new-tabset
               (if append
                 (append tabs (list tab))
                 (cons tab tabs)))
             (new-tabset
               (sort
                  tentative-new-tabset
                  #'(lambda (e1 e2)
                     (string-lessp
                       (format "%s" (car e1)) (format "%s" (car e2)))))))
        (tabbar-set-template tabset nil)
        (set tabset new-tabset)))))

;; AUTHOR:  Alp Aker -- https://github.com/alpaker/Frame-Bufs
;; @lawlist extracted/revised the function(ality) from said library.
(defun my-buffer-list (frame)
  ;; Remove dead buffers.
  (set-frame-parameter frame 'frame-bufs-buffer-list
    (delq nil (mapcar #'(lambda (x) (if (buffer-live-p x) x))
      (frame-parameter frame 'frame-bufs-buffer-list))))
  ;; Return the associated-buffer list.
  (frame-parameter frame 'frame-bufs-buffer-list))

(defun my-kill-buffer-fn ()
"This function is attached to a buffer-local `kill-buffer-hook'."
  (let ((frame (selected-frame))
        (current-buffer (current-buffer)))
    (when (memq current-buffer (my-buffer-list frame))
      (my-remove-buffer current-buffer frame))))

;; AUTHOR:  Alp Aker -- https://github.com/alpaker/Frame-Bufs
;; @lawlist extracted/revised the function(ality) from said library.
(defun my-add-buffer (&optional buf frame)
"Add BUF to FRAME's associated-buffer list if not already present."
(interactive)
  (let* ((buf (if buf buf (current-buffer)))
         (frame (if frame frame (selected-frame)))
         (associated-bufs (frame-parameter frame 'frame-bufs-buffer-list)))
    (unless (bufferp buf)
      (signal 'wrong-type-argument (list 'bufferp buf)))
    (unless (memq buf associated-bufs)
      (set-frame-parameter frame 'frame-bufs-buffer-list (cons buf associated-bufs)))
    (with-current-buffer buf
      (add-hook 'kill-buffer-hook 'my-kill-buffer-fn 'append 'local))
    (when tabbar-mode (tabbar-display-update))))

;; AUTHOR:  Alp Aker -- https://github.com/alpaker/Frame-Bufs
;; @lawlist extracted/revised the function(ality) from said library.
(defun my-remove-buffer (&optional buf frame)
"Remove BUF from FRAME's associated-buffer list."
(interactive)
  (let ((buf (if buf buf (current-buffer)))
        (frame (if frame frame (selected-frame))))
    (set-frame-parameter frame 'frame-bufs-buffer-list
      (delq buf (frame-parameter frame 'frame-bufs-buffer-list)))
    (when tabbar-mode (tabbar-display-update))))

;; AUTHOR:  Alp Aker -- https://github.com/alpaker/Frame-Bufs
;; @lawlist extracted/revised the function(ality) from said library.
(defun my-buffer-list-reset ()
    "Wipe the entire slate clean for the selected frame."
  (interactive)
    (modify-frame-parameters (selected-frame) (list (cons 'frame-bufs-buffer-list nil)))
    (when tabbar-mode (tabbar-display-update)))

(defun my-switch-tab-group ()
"Switch between tab group `A` and `N`."
(interactive)
  (let ((current-group (format "%s" (tabbar-current-tabset t)))
        (tab-buffer-list (mapcar
            #'(lambda (b)
                (with-current-buffer b
                  (list (current-buffer)
                        (buffer-name)
                        (funcall tabbar-buffer-groups-function))))
                 (funcall tabbar-buffer-list-function))))
    (catch 'done
      (mapc
        #'(lambda (group)
            (when (not (equal current-group
                          (format "%s" (car (car (cdr (cdr group)))))))
              (throw 'done (switch-to-buffer (car (cdr group))))))
        tab-buffer-list))))

(defface tabbar-selected-associated
  '((t :background "black" :foreground "yellow" :box (:line-width 2 :color "yellow")))
  "Face used for the selected tab -- associated with the `frame-bufs-buffer-list`."
  :group 'tabbar)

(defface tabbar-unselected-associated
  '((t :background "black" :foreground "white" :box (:line-width 2 :color "white")))
  "Face used for unselected tabs  -- associated with the `frame-bufs-buffer-list`."
  :group 'tabbar)

(defface tabbar-selected-unassociated
  '((t :background "black" :foreground "white" :box (:line-width 2 :color "firebrick")))
  "Face used for the selected tab -- UNassociated with the `frame-bufs-buffer-list`."
  :group 'tabbar)

(defface tabbar-unselected-unassociated
  '((t :background "black" :foreground "white" :box (:line-width 2 :color "blue")))
  "Face used for unselected tabs -- UNassociated with the `frame-bufs-buffer-list`."
  :group 'tabbar)

(setq tabbar-background-color "black")

(defsubst tabbar-line-tab (tab)
  "Return the display representation of tab TAB.
That is, a propertized string used as an `header-line-format' template
element.
Call `tabbar-tab-label-function' to obtain a label for TAB."
  (concat
    (propertize
      (if tabbar-tab-label-function
          (funcall tabbar-tab-label-function tab)
        tab)
      'tabbar-tab tab
      'local-map (tabbar-make-tab-keymap tab)
      'help-echo 'tabbar-help-on-tab
      'mouse-face 'tabbar-highlight
      'face
        (cond
          ((and
              (tabbar-selected-p tab (tabbar-current-tabset))
              (memq (current-buffer) (my-buffer-list (selected-frame))))
            'tabbar-selected-associated)
          ((and
              (not (tabbar-selected-p tab (tabbar-current-tabset)))
              (memq (current-buffer) (my-buffer-list (selected-frame))))
            'tabbar-unselected-associated)
          ((and
              (tabbar-selected-p tab (tabbar-current-tabset))
              (not (memq (current-buffer) (my-buffer-list (selected-frame)))))
            'tabbar-selected-unassociated)
          ((and
              (not (tabbar-selected-p tab (tabbar-current-tabset)))
              (not (memq (current-buffer) (my-buffer-list (selected-frame)))))
            'tabbar-unselected-unassociated))
      'pointer 'hand)
    tabbar-separator-value))

(define-key global-map "\C-c\C-r" 'my-buffer-list-reset)

(define-key global-map "\C-c\C-a" 'my-add-buffer)

(define-key global-map "\C-c\C-n" 'my-remove-buffer)

(define-key global-map (kbd "<M-s-right>") 'tabbar-forward)

(define-key global-map (kbd "<M-s-left>") 'tabbar-backward)

(define-key global-map [C-tab] 'my-switch-tab-group)

(tabbar-mode 1)

La seguente schermata mostra i due possibili raggruppamenti buffer / tab: (1) a sinistra è un raggruppamento di quei buffer / tab associati al frame chiamato SYSTEM[tabs giallo e bianco], con la lettera maiuscola "A" indicata nella mode-line; e (2) a destra è un raggruppamento di quei buffer / tab che NON sono associati al frame chiamato SYSTEM[tabs blu e rosso], con una lettera maiuscola "N" indicata nella linea di modalità.

Esempio


Ma l'OP non vuole "una tabbar per finestra", vuole una tabbar per frame e ogni tab nella tabbar dovrebbe rappresentare una "configurazione della finestra" (cioè diverse finestre) piuttosto che un buffer.
Stefan

5

Prendi in considerazione il controllo di elscreen , anche se in realtà non raggruppa i buffer.

Ciò che fa è raggruppare le finestre e fornire l'accesso a più layout (schede) che è possibile spostarsi rapidamente. Il mio flusso di lavoro ha spesso un po 'di codice Ruby e test associati in una schermata, mentre le mie note todo e Org sono in un'altra, e forse un buffer scratch per la redazione di query SQL è in una terza. Questo mi permette di saltare facilmente tra attività e progetti, anche se ogni schermata si basa sullo stesso pool di buffer.


3

E il mio plugin, centaur-tabs? Ha molte opzioni di configurazione, è davvero funzionale, è supportato da temi molto popolari come i temi del caolino e nel complesso è un pacchetto esteticamente gradevole ed estetico (secondo il feedback degli utenti). È disponibile in MELPA e si presenta così:

inserisci qui la descrizione dell'immagine


Questo sembra essere ancora un altro "ogni scheda rappresenta un buffer e ogni finestra ha la propria barra" non soluzione.
Stefan

Ho appena aggiunto una personalizzazione per mostrare i gruppi di schede anziché i nomi di scheda, quindi in una funzione si stabiliscono regole (ovvero raggruppa elisp e lisp in un gruppo, gruppo c e c ++ in un altro e così via) e nelle schede vengono mostrati quei gruppi.
Emmanuel Bustos

Non risponde ancora alla domanda, dove dovrebbe esserci una tabbar per frame (piuttosto che per finestra) e ogni tab rappresenta una configurazione di finestra.
Stefan

Ok, non ho capito. Investigherò e ci lavorerò!
Emmanuel Bustos

0

Ecco la mia configurazione, per quello che vale. È dotato di:

  • Operazione del mouse sulle schede ( mouse-2per chiudere, come nei browser , mouse-3 per aprirsi in una nuova finestra di Emacs, come in i3 )
  • Controlli da tastiera ( M-lefte le schede degli interruttori a destra, come in TMux / Schermo )
  • Colori (coerenti con la moe-darkconfigurazione " Tema Moe / " inclusa)
  • Raggruppamento (attualmente, Emacs *buffers*e "normale")
  • Aggiornamento automatico (con use-package )

TabBar

(use-package tabbar
  :ensure t
  :bind
  ("<M-left>" . tabbar-backward)
  ("<M-right>" . tabbar-forward)

  :config
  (set-face-attribute
   'tabbar-button nil
   :box '(:line-width 1 :color "gray19"))

  (set-face-attribute
   'tabbar-selected nil
   :foreground "orange"
   :background "gray19"
   :box '(:line-width 1 :color "gray19"))

  (set-face-attribute
   'tabbar-unselected nil
   :foreground "gray75"
   :background "gray25"
   :box '(:line-width 1 :color "gray19"))

  (set-face-attribute
   'tabbar-highlight nil
   :foreground "black"
   :background "orange"
   :underline nil
   :box '(:line-width 1 :color "gray19" :style nil))

  (set-face-attribute
   'tabbar-modified nil
   :foreground "orange red"
   :background "gray25"
   :box '(:line-width 1 :color "gray19"))

  (set-face-attribute
   'tabbar-selected-modified nil
   :foreground "orange red"
   :background "gray19"
   :box '(:line-width 1 :color "gray19"))

  (custom-set-variables
   '(tabbar-separator (quote (0.2))))

  (defun tabbar-buffer-tab-label (tab)
    "Return a label for TAB.
  That is, a string used to represent it on the tab bar."
    (let ((label  (if tabbar--buffer-show-groups
                      (format " [%s] " (tabbar-tab-tabset tab))
                    (format " %s " (tabbar-tab-value tab)))))
      (if tabbar-auto-scroll-flag
          label
        (tabbar-shorten
         label (max 1 (/ (window-width)
                         (length (tabbar-view
                                  (tabbar-current-tabset)))))))))

  (defun px-tabbar-buffer-select-tab (event tab)
    "On mouse EVENT, select TAB."
    (let ((mouse-button (event-basic-type event))
          (buffer (tabbar-tab-value tab)))
      (cond
       ((eq mouse-button 'mouse-2) (with-current-buffer buffer (kill-buffer)))
       ((eq mouse-button 'mouse-3) (pop-to-buffer buffer t))
       (t (switch-to-buffer buffer)))
      (tabbar-buffer-show-groups nil)))

  (defun px-tabbar-buffer-help-on-tab (tab)
    "Return the help string shown when mouse is onto TAB."
    (if tabbar--buffer-show-groups
        (let* ((tabset (tabbar-tab-tabset tab))
               (tab (tabbar-selected-tab tabset)))
          (format "mouse-1: switch to buffer %S in group [%s]"
                  (buffer-name (tabbar-tab-value tab)) tabset))
      (format "\
mouse-1: switch to %S\n\
mouse-2: kill %S\n\
mouse-3: Open %S in another window"
              (buffer-name (tabbar-tab-value tab))
              (buffer-name (tabbar-tab-value tab))
              (buffer-name (tabbar-tab-value tab)))))

  (defun px-tabbar-buffer-groups ()
    "Sort tab groups."
    (list (cond ((or
                  (eq major-mode 'dired-mode)
                  (string-equal "*" (substring (buffer-name) 0 1))) "emacs")
                (t "user"))))
  (setq tabbar-help-on-tab-function 'px-tabbar-buffer-help-on-tab
        tabbar-select-tab-function 'px-tabbar-buffer-select-tab
        tabbar-buffer-groups-function 'px-tabbar-buffer-groups)

  :init
  (tabbar-mode 1))

Allegato 1 - Tema Moe

(use-package moe-theme
  :ensure t
  :config
  (progn
    (load-theme 'moe-dark :no-confirm)
    (set-face-attribute 'fringe nil :background "gray19")))

Allegato 2 - Attiva / disattiva gli ultimi 2 buffer (macro KB)

(define-key global-map [(control tab)] (kbd "C-x b <return>")) 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.