Funzioni utili!

m0rp30/delete-blank-lines aka laluxx/delete-blank-lines

Prendendo spunto dalla condivisione fatta da @Codeko sui suoi keybind ho fatto questa sezione dove sara interessante vedere le nostre varie funzioni e parto subito da una sua funzione che trovo super utile ma che ho modificato

(defun m0rp30/delete-blank-lines ()
  "Standard behavior of delete-blank-line but if the point is on last line add one"
  (interactive)
  (delete-blank-lines)
  (if (eobp)
      (open-line 1)
    nil))

In pratica usa il comportamento standard di delete-blank-lines ma se, dopo aver cancellato l’ultima linea, ci si trova con il punto a fine buffer allora ne aggiunge una.
Prima che vedessi la funzione di @Codeko non conoscevo ne la funzione per delete-blank-lines ne tanto meno quella per controllare se ci si trova alla fine del buffer eobp.

E voi quali super funzioni vi siete fatti !?!?

p.s. le funzioni le nomino tutte m0rp30/… non per vanita o per prenderne il merito ma solo per pura semplicita di ricerca :smile: … quindi grazie a tutti del contributo !!!

laluxx/smart-increment-at-point

Il punto di forza è la sua intelligenza nel determinare automaticamente cosa modificare in base al contesto.
  • Se il cursore è su un numero: lo incrementa/decrementa
  • Se il cursore è su un colore hex: lo schiarisce/scurisce
  • Se non è su nessuno dei due: modifica l’opacità della finestra

increment-trimmed

Le trovo molto utile per le macro

macro

Implementazione:

 (defun laluxx/adjust-hex-color (hex-string delta)
  "Adjust each RGB component of HEX-STRING by DELTA."
  (let* ((rgb-str (substring hex-string 1))  ; Remove # prefix
         (rgb-val (string-to-number rgb-str 16))
         (r (lsh rgb-val -16))
         (g (logand (lsh rgb-val -8) #xFF))
         (b (logand rgb-val #xFF))
         (new-r (min 255 (max 0 (+ r delta))))
         (new-g (min 255 (max 0 (+ g delta))))
         (new-b (min 255 (max 0 (+ b delta)))))
    (format "#%02x%02x%02x" new-r new-g new-b)))

(defun laluxx/adjust-background-opacity (delta)
  "Adjust the background opacity by DELTA."
  (let* ((current-alpha (or (frame-parameter nil 'alpha-background) 100))
         (new-alpha (max 0 (min 100 (+ current-alpha delta)))))
    (set-frame-parameter nil 'alpha-background new-alpha)
    (message "Background opacity set to %d%%" new-alpha)))

(defun laluxx/smart-increment-at-point (&optional n)
  "Increment number, adjust hex color at point, or increase background opacity by N (default 1)."
  (interactive "p")
  (or n (setq n 1))
  (save-excursion
    (skip-chars-backward "0123456789abcdefABCDEF#")
    (cond
     ;; Hex color case
     ((looking-at "#[0-9a-fA-F]\\{6\\}")
      (let* ((hex-color (match-string 0))
             (new-color (laluxx/adjust-hex-color hex-color n)))
        (replace-match new-color)))
     ;; Number case
     ((looking-at "[0-9]+")
      (replace-match
       (number-to-string (+ (string-to-number (match-string 0)) n))))
     ;; Adjust background opacity if no number or hex color found
     (t (laluxx/adjust-background-opacity n)))))

(defun laluxx/smart-decrement-at-point (&optional n)
  "Decrement number, adjust hex color at point, or decrease background opacity by N (default 1)."
  (interactive "p")
  (laluxx/smart-increment-at-point (- (or n 1))))

;; Key bindings
(global-set-key (kbd "<XF86AudioRaiseVolume>") 'laluxx/smart-increment-at-point)
(global-set-key (kbd "<XF86AudioLowerVolume>") 'laluxx/smart-decrement-at-point)
(global-set-key (kbd "C-x <up>") 'laluxx/smart-increment-at-point)
(global-set-key (kbd "C-x <down>") 'laluxx/smart-decrement-at-point)

2 Likes

@m0rp30

Secondo me sarebbe meglio postare una funzione alla volta in questo thread. Quando ci sono molte funzioni in un unico post, diventa più difficile:

  • Parsare e seguire la discussione
  • Trovare velocemente una funzione specifica
  • Linkare o riferirsi a una particolare funzione

Così ogni funzione può avere il suo spazio per discussione, analisi e miglioramenti. Che ne pensi?

1 Like

Hai ragione … provvedo subito a splittare le mie !!!

m0rp30/duplicate-line aka rc/duplicate-line

Altra funzione, che ho rubacchiato da Tsoding, e’ quella per duplicare le linee rimanendo nel punto in cui ci si trovava … super utile …

(defun m0rp30/duplicate-line ()
  "Duplicate current line"
  (interactive)
  (let ((column (- (point) (point-at-bol)))
        (line (let ((s (thing-at-point 'line t)))
                (if s (string-remove-suffix "\n" s) ""))))
    (move-end-of-line 1)
    (newline)
    (insert line)
    (move-beginning-of-line 1)
    (forward-char column)))

Non l’ho analizzata tropo ma imita il comportamento standard di duplicate-line ma porta il punto nella medesima posizione, in termini di colonna, sulla nuova riga.
Mancano le funzionalita di creare N nuove linee ma ci sto lavorando :smile:

m0rp30/goto-line-relative

Siccome io uso la visualizzazione dei numeri di riga in modalita relativa

per spostarmi agilmente nella riga che voglio uso questa funzione:

(defun m0rp30/goto-line-relative (relative-line-number)
  "Go to the relative line by the point"
  (interactive "nInsert number: ")
  (goto-line (+ (line-number-at-pos) relative-line-number)))

che richiede l’inserimento del numero di righe di cui ci si vuole muovere, se il numero e’ negativo si sposta verso l’alto, per dire se mi trovo nella posizione dello screeshot e voglio andare alla riga che inizia con generi chiamo la funzione e gli passo -4 se voglio andare alla riga che inizia con **Funzione ** gli passo 7

Banalissima, alla posizione corrente aggiungo il valore che passo e se e’ negativo + per - fa meno quindi si sposta in alto !!!

m0rp30/move-line-up and m0rp30/move-line-down

Altre due funzioni molto utili sono quelle per spostare la linea corrente su o giu e sono

(defun m0rp30/move-line-up ()
  "Muove line at point up"
  (interactive)
  (transpose-lines 1)
  (forward-line -2))

(defun m0rp30/move-line-down ()
  "Muove line at point down"
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1))

In pratica transpose-line sposta la linea su cui ci si trova lasciando il punto quindi con forward-line sposta il punto su o giu in base al valore passatogli.
La voglio implementare aggiungendo il fatto che il punto deve rimanere nella posizione di colonna corrente e che se c’e’ una selezione deve spostare solo quella.

m0rp30/random-list-element

Questa e’ una di quelle funzioni di cui vai super fiero ma non te ne fai davvero nulla :crazy_face:

(defun m0rp30/random-list-element (list-of-element)
  "Get a list and return a random item from the list"
  (if (and (not (null list-of-element)) (listp list-of-element))
      (nth
       (random (length list-of-element)) list-of-element)
    "error: the list is not a list or empty"))

Non ricordo per quale motivo mi serviva, in’oltre credo che esista pure una funzione standard che lo fa, ma in poche parole prende una lista e ritorna uno a caso tra quelli passati

Anche queste sicure che te le rubo :crazy_face:

Questa idea è molto figa!

Adesso sto in trasferta per lavoro e devo finire un paio di cose per domani, ma in futuro carico pure io qualcosa, bel thread

2 Likes

Questa funzione permette di eseguire comandi da root. Quando si utilizza esce fuori un prompt per inserire la password dell’account root, e poi esegue il comando nel nuovo contesto.

(defun my/tool-execute-as-root (command)
  (interactive "Execute as root: ")
   (with-temp-buffer
     (cd "/sudo::/")
     (async-shell-command command))    
  )

Devo ancora indagare bene per quanto tempo salva la sessione da root.

1 Like

Questa fa il refresh del file corrente. Onestamente non so se ne esiste una built-in in emacs, ma avevo bisogno di fare refresh veloci, e me la sono scritta anni fa

(defun refresh-current-file()
  (interactive)
  (let ((current-buffer-name (buffer-name (window-buffer (minibuffer-selected-window))))
	(current-file-name (buffer-file-name (window-buffer (minibuffer-selected-window))))
	)    
    (kill-buffer-if-not-modified current-buffer-name)
    (find-file current-file-name)))
1 Like

Queste due funzioni combinate mi permettono di selezionare un indirizzo IP tra quelli disponibili. È da un po’ che non la rivedo, quindi secondo me può essere migliorata, ma penso sia utile a prescindere. Utilizza il comando ip a per ottenere la lista delle network interfaces, e poi estrare dalla stringa i vari indirizzi IP (per adesso IPv4).

(defun list-of-IPs()
  (interactive)
  (shell-command "ip a")
  (switch-to-buffer "*Shell Command Output*")
  (let ((done nil)
	(start-p -1)
	(end-p -1)
	(list-of-ips nil))

    (while (not done)
      (condition-case ex
	  (search-forward "inet ")
	('error (setq done 't)))

      (when (not done)
	(setq start-p (point))
	(search-forward "/")
	(setq end-p (- (point) 1))
	;; (message "%s" (buffer-substring start-p end-p))
	(setq list-of-ips (cons (string-trim (buffer-substring start-p end-p))
				list-of-ips))))
    (kill-current-buffer)
    (delete-other-windows)
    list-of-ips))

Viene poi utilizzata dalla seguente tramite un wrapper ivy. Questo tipo di pattern lo utilizzo molto spesso: ho una funzione che fa robe e ritorna una lista di possibilità, e poi la wrappo con una chiamata ad ivy per avere una selezione interattiva

(defun ip()
  (interactive)
  (ivy-read "Choose IP: " (list-of-IPs) :action (lambda (x) (kill-new x))))
1 Like

Questa per convertire caratteri ASCII in caratteri hex. Ne ho fatte altre anche per altri encodings, ma metto questa giusto per far capire l’idea

(defun my/txt2hex (beg end)
  "opens new buffer *out* which contains the selected text as
well as the hexadecimal bytes of the text."
  (interactive
   (if (use-region-p)
       (list (region-beginning) (region-end))
     (list nil nil)))
  (if (and beg end)
      (progn
	(let ((word (buffer-substring-no-properties beg end)))
	  (switch-to-buffer-other-window "*out*")
	  (erase-buffer)	  

	  ;; -- first, for each word
	  (dotimes (i (length word))
	    ;; -- write char and hex
	    (insert (format "%c -> 0x%X\n" (aref word i) (aref word i))))
	  
	  (insert "\n")
	  
	  ;; -- then, write each hex byte in a row
	  (insert "0x")
	  (dotimes (i (length word))
	    (insert (format "%X" (aref word i))))

	  ))))
1 Like

Questa per aprire un piccolo buffer vterm in basso. La utilizzo quando devo eseguire un comando al volo e poi chiudere la shell

(defun my/vterm-window-split ()
  (interactive)
  (split-window-below -15)
  (other-window 1)
  (switch-to-buffer "*vterminal<1>*"))

@leo cosa intendi per selezionare che non ho capito, cioe’ in che ambito per cambiare ip alla macchina ?!?

Questa mi interessa perche’ non ho mai approfondito bene come si passa una regione selezionata ed e’ una cosa che mi interessa ed e’ utile

selezionare = copiare nel kill-ring. Non va a modificare roba. Semplicemente, te lo mette nella clipboard di emacs così che lo puoi incollare dove vuoi dopo

Il codice che viene eseguito da ivy quando clicchi su un elemento è questo

:action (lambda (x) (kill-new x)

Ovvero va a fare il kill-new sull’elemento selezionato dal prompt di ivy.

1 Like

Prova auto-revert-mode

Avevo visto questa funzione guardando un tuo video e ho deciso di implementarla a modo mio.
È stata molto utile durante lo sviluppo della mia shell per i keybinds, specialmente per la conversione dei control characters rappresentabili in Emacs con la funzionequoted-insert
^M (C-m nel terminale) con C-q C-m.

Potrebbe supportare piu conversioni, si potrebbe pure chiedere la base nel minibuffer.

;; TODO Color the output message for better readabilty
(defun laluxx/convert (input)
  "Convert INPUT (in decimal, hexadecimal with 0x, octal with 0o, binary with 0b prefix, or ASCII)
to decimal, hexadecimal, octal, binary formats, and ASCII characters. If a region is active, use its contents as INPUT."
  (interactive
   (list (if (use-region-p)
             (buffer-substring-no-properties (region-beginning) (region-end))
           (read-string "Enter a number (decimal, hexadecimal with 0x, octal with 0o, binary with 0b prefix, or ASCII): "))))
  (let* ((decimal
          (cond
           ;; Binary input
           ((string-prefix-p "0b" input)
            (string-to-number (substring input 2) 2))
           ;; Hexadecimal input
           ((string-prefix-p "0x" input)
            (string-to-number (substring input 2) 16))
           ;; Octal input
           ((string-prefix-p "0o" input)
            (string-to-number (substring input 2) 8))
           ;; Decimal input
           ((string-match-p "\\`[0-9]+\\'" input)
            (string-to-number input))
           ;; ASCII input
           (t
            (let ((ascii-value (string-to-char input)))
              (if (characterp ascii-value)
                  (progn
                    (message "Input is ASCII: %s" input)
                    ascii-value)
                nil)))))
         (binary (format "%s" decimal))
         (hexadecimal (format "0x%X" decimal))
         (octal (format "0o%o" decimal))
         (ascii-char (if (and (characterp decimal) (< decimal 128))
                         (format "'%c'" (string-to-char (string decimal)))
                       "N/A")))
    (message "Input: %s ➜ Decimal: %d,  Hexadecimal: %s,  Octal: %s,  Binary: 0b%s,  ASCII: %s"
             input decimal hexadecimal octal binary ascii-char)))

2 Likes