17 changed files with 1161 additions and 1 deletions
-
6custom.el
-
28elpa/company-nixos-options-0.0.1/company-nixos-options-autoloads.el
-
2elpa/company-nixos-options-0.0.1/company-nixos-options-pkg.el
-
90elpa/company-nixos-options-0.0.1/company-nixos-options.el
-
22elpa/nixos-options-0.0.1/nixos-options-autoloads.el
-
2elpa/nixos-options-0.0.1/nixos-options-pkg.el
-
129elpa/nixos-options-0.0.1/nixos-options.el
-
232elpa/pacfiles-mode-1.0/pacfiles-buttons.el
-
62elpa/pacfiles-mode-1.0/pacfiles-mode-autoloads.el
-
13elpa/pacfiles-mode-1.0/pacfiles-mode-pkg.el
-
270elpa/pacfiles-mode-1.0/pacfiles-mode.el
-
36elpa/pacfiles-mode-1.0/pacfiles-utils.el
-
84elpa/pacfiles-mode-1.0/pacfiles-win.el
-
1elpa/sed-mode-1.0.signed
-
29elpa/sed-mode-1.0/sed-mode-autoloads.el
-
2elpa/sed-mode-1.0/sed-mode-pkg.el
-
154elpa/sed-mode-1.0/sed-mode.el
@ -0,0 +1,28 @@ |
|||
;;; company-nixos-options-autoloads.el --- automatically extracted autoloads |
|||
;; |
|||
;;; Code: |
|||
|
|||
(add-to-list 'load-path (directory-file-name |
|||
(or (file-name-directory #$) (car load-path)))) |
|||
|
|||
|
|||
;;;### (autoloads nil "company-nixos-options" "company-nixos-options.el" |
|||
;;;;;; (0 0 0 0)) |
|||
;;; Generated autoloads from company-nixos-options.el |
|||
|
|||
(autoload 'company-nixos-options "company-nixos-options" "\ |
|||
|
|||
|
|||
\(fn COMMAND &optional ARG &rest IGNORED)" t nil) |
|||
|
|||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "company-nixos-options" '("company-nixos-"))) |
|||
|
|||
;;;*** |
|||
|
|||
;; Local Variables: |
|||
;; version-control: never |
|||
;; no-byte-compile: t |
|||
;; no-update-autoloads: t |
|||
;; coding: utf-8 |
|||
;; End: |
|||
;;; company-nixos-options-autoloads.el ends here |
|||
@ -0,0 +1,2 @@ |
|||
;;; Generated package description from company-nixos-options.el -*- no-byte-compile: t -*- |
|||
(define-package "company-nixos-options" "0.0.1" "Company Backend for nixos-options" '((company "0.8.0") (nixos-options "0.0.1") (cl-lib "0.5.0")) :commit "5fc8fa29bea9dd8e9c822af92f9bc6ddc223635f" :authors '(("Diego Berrocal" . "cestdiego@gmail.com") ("Travis B. Hartwell" . "nafai@travishartwell.net")) :maintainer '("Diego Berrocal" . "cestdiego@gmail.com") :keywords '("unix") :url "http://www.github.com/travisbhartwell/nix-emacs/") |
|||
@ -0,0 +1,90 @@ |
|||
;;; company-nixos-options.el --- Company Backend for nixos-options |
|||
|
|||
;; Copyright (C) 2015 Diego Berrocal and Travis B. Hartwell |
|||
|
|||
;; Author: Diego Berrocal <cestdiego@gmail.com> |
|||
;; Travis B. Hartwell <nafai@travishartwell.net> |
|||
;; Created: 18 July 2015 |
|||
|
|||
;; Keywords: unix |
|||
;; Package-Version: 0.0.1 |
|||
;; Package-Commit: 5fc8fa29bea9dd8e9c822af92f9bc6ddc223635f |
|||
;; Homepage: http://www.github.com/travisbhartwell/nix-emacs/ |
|||
;; Version: "0.1.0" |
|||
;; Package-Requires: ((company "0.8.0") (nixos-options "0.0.1") (cl-lib "0.5.0")) |
|||
|
|||
;; This file is not part of GNU Emacs. |
|||
|
|||
;;; License: GPLv3 |
|||
|
|||
;;; Commentary: |
|||
|
|||
;; Useful functions for exploring the NixOS options. Inspired by |
|||
;; https://nixos.org/nixos/options.html. |
|||
|
|||
;;; Code: |
|||
(require 'nixos-options) |
|||
(require 'company) |
|||
(require 'cl-lib) |
|||
|
|||
(defvar company-nixos-options-keywords |
|||
(mapcar (lambda (nixos-option) |
|||
(list (nixos-options-get-name nixos-option) |
|||
(nixos-options-get-description nixos-option))) |
|||
nixos-options)) |
|||
|
|||
(defun company-nixos-options--make-candidate (candidate) |
|||
(let* ((text (car candidate)) |
|||
(meta (cadr candidate))) |
|||
(propertize text 'meta meta))) |
|||
|
|||
;; The following two functions are borrowed from company-anaconda |
|||
(defun company-nixos-options--get-property (property candidate) |
|||
"Return the property PROPERTY of completion candidate CANDIDATE." |
|||
(let ((item (get-text-property 0 'item candidate))) |
|||
(plist-get item property))) |
|||
|
|||
(defun company-nixos-options--doc-buffer (candidate) |
|||
"Return documentation buffer for chosen CANDIDATE." |
|||
(let ((doc (nixos-options-get-documentation-for-option |
|||
(nixos-options-get-option-by-name candidate)))) |
|||
(and doc (nixos-options-doc-buffer doc)))) |
|||
|
|||
(defun company-nixos-options--candidates (prefix) |
|||
(let (res) |
|||
(dolist (item company-nixos-options-keywords) |
|||
(when (string-prefix-p prefix (car item)) |
|||
(push (company-nixos-options--make-candidate item) res))) |
|||
res)) |
|||
|
|||
(defun company-nixos-options--meta (candidate) |
|||
(format "This will use %s of %s" |
|||
(get-text-property 0 'meta candidate) |
|||
(substring-no-properties candidate))) |
|||
|
|||
(defun company-nixos-options--annotation (candidate) |
|||
(format " -> %s" (get-text-property 0 'meta candidate))) |
|||
|
|||
(defun company-nixos--grab-symbol () |
|||
(buffer-substring (point) (save-excursion (skip-syntax-backward "w_.") |
|||
(point)))) |
|||
|
|||
(defun company-nixos-options--prefix () |
|||
"Grab prefix at point." |
|||
(or (company-nixos--grab-symbol) |
|||
'stop)) |
|||
|
|||
;;;###autoload |
|||
(defun company-nixos-options (command &optional arg &rest ignored) |
|||
(interactive (list 'interactive)) |
|||
(cl-case command |
|||
(interactive (company-begin-backend 'company-nixos-options)) |
|||
(prefix (company-nixos-options--prefix)) |
|||
(candidates (company-nixos-options--candidates arg)) |
|||
(doc-buffer (company-nixos-options--doc-buffer arg)) |
|||
;; (annotation (company-nixos-options--annotation arg)) |
|||
(meta (company-nixos-options--meta arg)))) |
|||
|
|||
(provide 'company-nixos-options) |
|||
|
|||
;;; company-nixos-options.el ends here |
|||
@ -0,0 +1,22 @@ |
|||
;;; nixos-options-autoloads.el --- automatically extracted autoloads |
|||
;; |
|||
;;; Code: |
|||
|
|||
(add-to-list 'load-path (directory-file-name |
|||
(or (file-name-directory #$) (car load-path)))) |
|||
|
|||
|
|||
;;;### (autoloads nil "nixos-options" "nixos-options.el" (0 0 0 0)) |
|||
;;; Generated autoloads from nixos-options.el |
|||
|
|||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "nixos-options" '("define-nixos-options-item" "nixos-options"))) |
|||
|
|||
;;;*** |
|||
|
|||
;; Local Variables: |
|||
;; version-control: never |
|||
;; no-byte-compile: t |
|||
;; no-update-autoloads: t |
|||
;; coding: utf-8 |
|||
;; End: |
|||
;;; nixos-options-autoloads.el ends here |
|||
@ -0,0 +1,2 @@ |
|||
;;; Generated package description from nixos-options.el -*- no-byte-compile: t -*- |
|||
(define-package "nixos-options" "0.0.1" "Interface for browsing and completing NixOS options." '((emacs "24") (json "1.4")) :commit "5fc8fa29bea9dd8e9c822af92f9bc6ddc223635f" :authors '(("Diego Berrocal" . "cestdiego@gmail.com") ("Travis B. Hartwell" . "nafai@travishartwell.net")) :maintainer '("Diego Berrocal" . "cestdiego@gmail.com") :keywords '("unix") :url "http://www.github.com/travisbhartwell/nix-emacs/") |
|||
@ -0,0 +1,129 @@ |
|||
;;; nixos-options.el --- Interface for browsing and completing NixOS options. |
|||
|
|||
;; Copyright (C) 2015 Diego Berrocal and Travis B. Hartwell |
|||
|
|||
;; Author: Diego Berrocal <cestdiego@gmail.com> |
|||
;; Travis B. Hartwell <nafai@travishartwell.net> |
|||
;; Created: 18 July 2015 |
|||
|
|||
;; Keywords: unix |
|||
;; Package-Version: 0.0.1 |
|||
;; Package-Commit: 5fc8fa29bea9dd8e9c822af92f9bc6ddc223635f |
|||
;; Homepage: http://www.github.com/travisbhartwell/nix-emacs/ |
|||
;; Version: 0.0.1 |
|||
;; Package-Requires: ((emacs "24") (json "1.4")) |
|||
|
|||
;; This file is not part of GNU Emacs. |
|||
|
|||
;;; License: GPLv3 |
|||
|
|||
;;; Commentary: |
|||
|
|||
;; Useful functions for exploring the NixOS options. Inspired by |
|||
;; https://nixos.org/nixos/options.html. |
|||
|
|||
;;; Code: |
|||
|
|||
(require 'json) |
|||
|
|||
(defvar nixos-options-name-indent-amount 0 |
|||
"Indent by the maximum length, plus a colon, plus two spaces.") |
|||
|
|||
;; Macros for defining constants and functions for working with options |
|||
(defmacro define-nixos-options-item (item long-name) |
|||
(let* ((name-const (intern (concat "nixos-options-" item))) |
|||
(long-name-const (intern (concat "nixos-options-" item "-long-name"))) |
|||
(long-name-length-plus-padding (+ 3 (length long-name))) |
|||
(long-name-docstring (format "The long description for %s." item)) |
|||
(item-getter (intern (concat "nixos-options-get-" item))) |
|||
(item-getter-docstring |
|||
(format "Get the value of %s from OPTION." item)) |
|||
(item-display (intern (concat "nixos-options-display-" item))) |
|||
(item-display-docstring |
|||
(format "Display the value for %s from OPTION." item))) |
|||
`(progn |
|||
(defconst ,name-const ,item) |
|||
(defconst ,long-name-const ,long-name ,long-name-docstring) |
|||
(if (> ,long-name-length-plus-padding nixos-options-name-indent-amount) |
|||
(setq nixos-options-name-indent-amount |
|||
,long-name-length-plus-padding)) |
|||
(defun ,item-getter (option) |
|||
,item-getter-docstring |
|||
(cdr (assoc ,name-const option))) |
|||
(defun ,item-display (option) |
|||
,item-display-docstring |
|||
(let ((item (,item-getter option)) |
|||
(format-string |
|||
(format "%%-%ds %%s\n" nixos-options-name-indent-amount))) |
|||
(if (not (null item)) |
|||
(format format-string (concat ,long-name-const ":") item) |
|||
"")))))) |
|||
|
|||
(define-nixos-options-item "name" "Name") |
|||
(define-nixos-options-item "type" "Type") |
|||
(define-nixos-options-item "description" "Description") |
|||
(define-nixos-options-item "default" "Default value") |
|||
(define-nixos-options-item "example" "Example value") |
|||
(define-nixos-options-item "declarations" "Declared in") |
|||
|
|||
(defvar nixos-options-json-file |
|||
(let* ((cmd |
|||
"nix-build --no-out-link '<nixpkgs/nixos/release.nix>' -A options") |
|||
(dir (replace-regexp-in-string "\n\\'" "" |
|||
(shell-command-to-string cmd)))) |
|||
(expand-file-name "share/doc/nixos/options.json" dir)) |
|||
"Location of the options file.") |
|||
|
|||
(defun nixos-options--boolean-string (value) |
|||
"Return the string representation of the boolean VALUE. |
|||
Returns VALUE unchanged if not a boolean." |
|||
(cond ((eq value 't) "true") |
|||
((eq value :json-false) "false") |
|||
(t value))) |
|||
|
|||
(defun nixos-options--make-alist (option) |
|||
(let ((name (car option)) |
|||
(data (cdr option)) |
|||
(default (nixos-options-get-default option)) |
|||
(example (nixos-options-get-example option))) |
|||
(progn |
|||
(if (not (null default)) |
|||
(setcdr (assoc nixos-options-default option) |
|||
(nixos-options--boolean-string default))) |
|||
(if (not (null example)) |
|||
(setcdr (assoc nixos-options-example option) |
|||
(nixos-options--boolean-string example))) |
|||
(add-to-list 'data `(,nixos-options-name . ,name)) |
|||
`(,name . ,data)))) |
|||
|
|||
(defvar nixos-options |
|||
(let* ((json-key-type 'string) |
|||
(raw-options (json-read-file nixos-options-json-file))) |
|||
(mapcar 'nixos-options--make-alist raw-options))) |
|||
|
|||
(defun nixos-options-get-documentation-for-option (option) |
|||
(concat (nixos-options-display-name option) |
|||
(nixos-options-display-type option) |
|||
(nixos-options-display-description option) |
|||
(nixos-options-display-default option) |
|||
(nixos-options-display-example option) |
|||
(nixos-options-display-declarations option))) |
|||
|
|||
;; Borrowed from anaconda-mode |
|||
(defun nixos-options-doc-buffer (doc) |
|||
"Display documentation buffer with contents DOC." |
|||
(let ((buf (get-buffer-create "*nixos-options-doc*"))) |
|||
(with-current-buffer buf |
|||
(view-mode -1) |
|||
(erase-buffer) |
|||
(insert doc) |
|||
(goto-char (point-min)) |
|||
(view-mode 1) |
|||
buf))) |
|||
|
|||
(defun nixos-options-get-option-by-name (name) |
|||
(assoc name nixos-options)) |
|||
|
|||
(provide 'nixos-options) |
|||
|
|||
;;; nixos-options.el ends here |
|||
@ -0,0 +1,232 @@ |
|||
;;; pacfiles-buttons.el --- the buttons of pacfiles-mode --- -*- lexical-binding: t; -*- |
|||
|
|||
;;; Commentary: |
|||
;; Definitions that deal with buttons and their fonts. |
|||
;; |
|||
;;; Code: |
|||
|
|||
(defgroup pacfiles-button-faces nil |
|||
"Faces for the buttons used in pacfiles-mode." |
|||
:group 'pacfiles) |
|||
|
|||
(defface pacfiles--apply-all |
|||
'((t (:inherit 'button :height 1.3))) |
|||
"Face for the Apply All button." |
|||
:group 'pacfiles-button-faces) |
|||
|
|||
(defface pacfiles--discard-all |
|||
'((t (:inherit 'button :height 1.3))) |
|||
"Face for the Apply All button." |
|||
:group 'pacfiles-button-faces) |
|||
|
|||
(defface pacfiles--discard |
|||
'((t (:inherit 'warning :weight bold :underline t))) |
|||
"Face for the Apply All button." |
|||
:group 'pacfiles-button-faces) |
|||
|
|||
(defface pacfiles--delete |
|||
'((t (:inherit 'error :weight bold :underline t))) |
|||
"Face for the Apply All button." |
|||
:group 'pacfiles-button-faces) |
|||
|
|||
|
|||
(define-button-type 'pacfiles--button-apply-all |
|||
'face 'pacfiles--apply-all |
|||
'follow-link t) |
|||
|
|||
(define-button-type 'pacfiles--button-discard-all |
|||
'face 'pacfiles--discard-all |
|||
'follow-link t) |
|||
|
|||
(define-button-type 'pacfiles--button-apply |
|||
'face 'button |
|||
'follow-link t) |
|||
|
|||
(define-button-type 'pacfiles--button-discard |
|||
'face 'pacfiles--discard |
|||
'follow-link t) |
|||
|
|||
(define-button-type 'pacfiles--button-delete |
|||
'face 'pacfiles--delete |
|||
'follow-link t) |
|||
|
|||
(define-button-type 'pacfiles--button-generic |
|||
'face 'button |
|||
'follow-link t) |
|||
|
|||
|
|||
(defvar pacfiles-activate-no-confirm nil |
|||
"Do not ask for user input when applying or discarding a merged file.") |
|||
|
|||
(defvar pacfiles--inhibit-button-revert nil |
|||
"Clicking a button does not revert the pacfiles list buffer.") |
|||
|
|||
(defun pacfiles--insert-merge-button (file-pair) |
|||
"Insert a button to merge FILE-PAIR. |
|||
|
|||
To determine the file-pair against which FILE will be merged, the extension of |
|||
FILE is removed." |
|||
(let* ((update-file (car file-pair)) |
|||
(base-file (file-name-sans-extension update-file))) |
|||
(if (file-exists-p base-file) |
|||
(progn |
|||
;; Insert button that merges two files. |
|||
(insert-text-button "[merge]" |
|||
'help-echo (format "Start merging '%s' and '%s'." |
|||
(file-name-nondirectory update-file) |
|||
(file-name-nondirectory base-file)) |
|||
'action `(lambda (_) |
|||
(ediff-merge-files ,update-file ,base-file nil |
|||
;; location of the merged file-pair |
|||
,(cdr file-pair))) |
|||
'type 'pacfiles--button-generic) |
|||
(insert " ")) |
|||
;; The base file doesn't exist. |
|||
;; Insert button that just copies the update to the merge file. |
|||
(insert-text-button "[merge]" |
|||
'help-echo (format "Merge '%s'." |
|||
(file-name-nondirectory update-file)) |
|||
'action `(lambda (_) |
|||
(when (y-or-n-p |
|||
(format "Base file '%s' not found. Use '%s' as is? " |
|||
,base-file ,update-file)) |
|||
(copy-file ,update-file ,(cdr file-pair)) |
|||
(when (not pacfiles--inhibit-button-revert) (revert-buffer t t)))) |
|||
'type 'pacfiles--button-generic) |
|||
(insert " ")))) |
|||
|
|||
(defun pacfiles--insert-view-merge-button (file-pair) |
|||
"Insert a button that displays the merge in FILE-PAIR." |
|||
(let* ((file-update (car file-pair)) |
|||
(file-base (file-name-sans-extension file-update)) |
|||
(file-merge (cdr file-pair))) |
|||
(insert-text-button "[view]" |
|||
'help-echo (format "View the merge of '%s' with '%s'." |
|||
(file-name-nondirectory file-update) |
|||
(file-name-nondirectory file-base)) |
|||
'action `(lambda (_) |
|||
(let ((window (split-window-right))) |
|||
(select-window window) |
|||
(set-window-buffer window |
|||
(pacfiles--create-view-buffer |
|||
(file-name-nondirectory ,file-base) ,file-merge)))) |
|||
'type 'pacfiles--button-generic) |
|||
(insert " "))) |
|||
|
|||
(defun pacfiles--insert-diff-button (file-update) |
|||
"Insert a button that displays a diff of the update FILE-UPDATE and its base file." |
|||
(let ((file-base (file-name-sans-extension file-update))) |
|||
(if (file-exists-p file-base) |
|||
(progn |
|||
(insert-text-button "[diff]" |
|||
'help-echo (format "Diff '%s' with '%s'." |
|||
(file-name-nondirectory file-update) |
|||
(file-name-nondirectory file-base)) |
|||
'action `(lambda (_) (ediff-files ,file-update ,file-base)) |
|||
'type 'pacfiles--button-generic) |
|||
(insert " ")) |
|||
;; Replace the diff button with spaces |
|||
(insert " ")))) |
|||
|
|||
(defun pacfiles--insert-apply-button (file-pair) |
|||
"Insert a button that copies the `cdr' of FILE-PAIR to its `car'." |
|||
(let* ((merge-file (cdr file-pair)) |
|||
(update-file (car file-pair)) |
|||
(destination-file (file-name-sans-extension update-file))) |
|||
(insert-text-button "[apply]" |
|||
'help-echo (format "Apply the merge of '%s' and '%s' to the file system." |
|||
(file-name-nondirectory update-file) |
|||
(file-name-sans-extension (file-name-nondirectory update-file))) |
|||
'action `(lambda (_) |
|||
(when (or pacfiles-activate-no-confirm |
|||
(y-or-n-p (format "Apply the merge and overwrite '%s'? " |
|||
,destination-file))) |
|||
;; Copy and keep the destination file's permissions and user/group |
|||
(let* ((dst-file (pacfiles--add-sudo-maybe ,destination-file :write)) |
|||
(dst-attrs (file-attributes dst-file 'integer)) |
|||
(dst-uid (file-attribute-user-id dst-attrs)) |
|||
(dst-gid (file-attribute-group-id dst-attrs)) |
|||
(dst-mode (file-modes dst-file))) |
|||
(copy-file ,merge-file dst-file t) |
|||
(set-file-modes dst-file dst-mode) |
|||
(tramp-set-file-uid-gid dst-file dst-uid dst-gid)) |
|||
;; Delete the merge and update files |
|||
(delete-file (pacfiles--add-sudo-maybe ,merge-file :write)) |
|||
(delete-file (pacfiles--add-sudo-maybe ,update-file :write)) |
|||
(when (not pacfiles--inhibit-button-revert) (revert-buffer t t)) |
|||
(message "Merge applied!"))) |
|||
'type 'pacfiles--button-apply) |
|||
(insert " "))) |
|||
|
|||
(defun pacfiles--insert-discard-button (file-pair) |
|||
"Insert button that deletes the `cdr' of FILE-PAIR from the file system." |
|||
(let ((merge-file (cdr file-pair)) |
|||
(update-file (car file-pair))) |
|||
(insert-text-button "[discard]" |
|||
'help-echo (format "Delete the merge of '%s' from the file system." |
|||
(file-name-sans-extension (file-name-nondirectory update-file))) |
|||
'action `(lambda (_) |
|||
(let ((del-file (pacfiles--add-sudo-maybe ,merge-file :write))) |
|||
(when (or pacfiles-activate-no-confirm |
|||
(y-or-n-p (format "Discard the merge between '%s' and '%s'? " |
|||
,update-file |
|||
,(file-name-sans-extension update-file)))) |
|||
(delete-file del-file) |
|||
(message "Merge discarded!"))) |
|||
(when (not pacfiles--inhibit-button-revert) (revert-buffer t t))) |
|||
'type 'pacfiles--button-discard) |
|||
(insert " "))) |
|||
|
|||
(defun pacfiles--insert-delete-button (file-pair) |
|||
"Insert a button that deletes the file in the `car' of FILE-PAIR." |
|||
(let ((update-file (car file-pair))) |
|||
(insert-text-button "[delete]" |
|||
'help-echo (format "Delete '%s' from the file system." |
|||
(file-name-nondirectory update-file)) |
|||
'action `(lambda (_) |
|||
(when (y-or-n-p (format "Delete '%s' permanently? " |
|||
,update-file)) |
|||
(delete-file (pacfiles--add-sudo-maybe ,update-file :write)) |
|||
(message "File deleted!")) |
|||
(when (not pacfiles--inhibit-button-revert) (revert-buffer t t))) |
|||
'type 'pacfiles--button-delete) |
|||
(insert " "))) |
|||
|
|||
(defun pacfiles--insert-footer-buttons () |
|||
"Insert the `apply all' and `discard all' buttons." |
|||
(insert-text-button "[Apply All]" |
|||
'help-echo "Write all merged files into the system." |
|||
'action (lambda (_) |
|||
(pacfiles--activate-all-buttons 'pacfiles--button-apply "apply")) |
|||
'type 'pacfiles--button-apply-all) |
|||
(insert " ") |
|||
(insert-text-button "[Discard All]" |
|||
'help-echo "Discard all merged files." |
|||
'action (lambda (_) |
|||
(pacfiles--activate-all-buttons 'pacfiles--button-discard "discard")) |
|||
'type 'pacfiles--button-discard-all)) |
|||
|
|||
(defun pacfiles--activate-all-buttons (activate-type action-name) |
|||
"Find all buttons with button type ACTIVATE-TYPE and activate them. |
|||
Use ACTION-NAME to display an appropriate warning message." |
|||
(when (y-or-n-p (concat (capitalize action-name) " all merged files? ")) |
|||
(save-excursion |
|||
(goto-char (point-min)) |
|||
;; Catch errors that `forward-button' might throw. |
|||
(condition-case nil |
|||
(let* ((pacfiles-activate-no-confirm t) ; do not ask the user |
|||
(pacfiles--inhibit-button-revert t) |
|||
(button (forward-button 1 nil nil)) |
|||
(type (button-type button))) |
|||
;; Iterate until we find the first footer button. |
|||
(while (not (eq type 'pacfiles--button-apply-all)) |
|||
(when (eq type activate-type) |
|||
(button-activate button)) |
|||
(setq button (forward-button 1 nil nil) |
|||
type (button-type button)))))) |
|||
(message "Done!") |
|||
(revert-buffer t t))) |
|||
|
|||
|
|||
(provide 'pacfiles-buttons) |
|||
;;; pacfiles-buttons.el ends here |
|||
@ -0,0 +1,62 @@ |
|||
;;; pacfiles-mode-autoloads.el --- automatically extracted autoloads |
|||
;; |
|||
;;; Code: |
|||
|
|||
(add-to-list 'load-path (directory-file-name |
|||
(or (file-name-directory #$) (car load-path)))) |
|||
|
|||
|
|||
;;;### (autoloads nil "pacfiles-buttons" "pacfiles-buttons.el" (0 |
|||
;;;;;; 0 0 0)) |
|||
;;; Generated autoloads from pacfiles-buttons.el |
|||
|
|||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pacfiles-buttons" '("pacfiles-"))) |
|||
|
|||
;;;*** |
|||
|
|||
;;;### (autoloads nil "pacfiles-mode" "pacfiles-mode.el" (0 0 0 0)) |
|||
;;; Generated autoloads from pacfiles-mode.el |
|||
|
|||
(defalias 'pacfiles 'pacfiles-start) |
|||
|
|||
(autoload 'pacfiles-start "pacfiles-mode" "\ |
|||
Find and manage pacman backup files in an Arch-based GNU/Linux system." t nil) |
|||
|
|||
(autoload 'pacfiles-revert-buffer-no-confirm "pacfiles-mode" "\ |
|||
Revert the pacfiles list buffer without asking for confirmation." t nil) |
|||
|
|||
(autoload 'pacfiles-mode "pacfiles-mode" "\ |
|||
|
|||
|
|||
\(fn)" t nil) |
|||
|
|||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pacfiles-mode" '("pacfiles-"))) |
|||
|
|||
;;;*** |
|||
|
|||
;;;### (autoloads nil "pacfiles-utils" "pacfiles-utils.el" (0 0 0 |
|||
;;;;;; 0)) |
|||
;;; Generated autoloads from pacfiles-utils.el |
|||
|
|||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pacfiles-utils" '("pacfiles--"))) |
|||
|
|||
;;;*** |
|||
|
|||
;;;### (autoloads nil "pacfiles-win" "pacfiles-win.el" (0 0 0 0)) |
|||
;;; Generated autoloads from pacfiles-win.el |
|||
|
|||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "pacfiles-win" '("pacfiles-"))) |
|||
|
|||
;;;*** |
|||
|
|||
;;;### (autoloads nil nil ("pacfiles-mode-pkg.el") (0 0 0 0)) |
|||
|
|||
;;;*** |
|||
|
|||
;; Local Variables: |
|||
;; version-control: never |
|||
;; no-byte-compile: t |
|||
;; no-update-autoloads: t |
|||
;; coding: utf-8 |
|||
;; End: |
|||
;;; pacfiles-mode-autoloads.el ends here |
|||
@ -0,0 +1,13 @@ |
|||
(define-package "pacfiles-mode" "1.0" "pacnew and pacsave merging tool" |
|||
'((emacs "26") |
|||
(cl-lib "0.5")) |
|||
:commit "180eea7ba33dc4fa5c116b01649c4e9ba3f43276" :authors |
|||
'(("Carlos G. Cordero <http://github/UndeadKernel>")) |
|||
:maintainer |
|||
'("Carlos G. Cordero" . "pacfiles@binarycharly.com") |
|||
:keywords |
|||
'("files" "pacman" "arch" "pacnew" "pacsave" "update" "linux") |
|||
:url "https://github.com/UndeadKernel/pacfiles-mode") |
|||
;; Local Variables: |
|||
;; no-byte-compile: t |
|||
;; End: |
|||
@ -0,0 +1,270 @@ |
|||
;;; pacfiles-mode.el --- pacnew and pacsave merging tool -*- lexical-binding: t; -*- |
|||
;; |
|||
;; Copyright (C) 2018 Carlos G. Cordero |
|||
;; |
|||
;; Author: Carlos G. Cordero <http://github/UndeadKernel> |
|||
;; Maintainer: Carlos G. Cordero <pacfiles@binarycharly.com> |
|||
;; Created: Oct 11, 2018 |
|||
;; Modified: Oct 11, 2018 |
|||
;; Version: 1.0 |
|||
;; Keywords: files pacman arch pacnew pacsave update linux |
|||
;; URL: https://github.com/UndeadKernel/pacfiles-mode |
|||
;; Package-Requires: ((emacs "26") (cl-lib "0.5")) |
|||
;; |
|||
;; This file is not part of GNU Emacs. |
|||
;; |
|||
;;; Commentary: |
|||
;; |
|||
;; `pacfiles-mode' is an Emacs major mode to manage `.pacnew` and `.pacsave` |
|||
;; files left by Arch's pacman. To merge files, *pacfiles-mode* automatically |
|||
;; creates an Ediff merge session that a user can interact with. After finishing |
|||
;; the Ediff merge session, *pacfiles-mode* cleans up the mess that Ediff leaves |
|||
;; behind. *pacfiles-mode* also takes care of keeping the correct permissions of |
|||
;; merged files, and requests passwords (with TRAMP) to act as root when needed. |
|||
;; |
|||
;; Start the major mode using the command `pacfiles' or `pacfiles/start'. |
|||
;; |
|||
;;; Code: |
|||
|
|||
(require 'pacfiles-buttons) |
|||
(require 'pacfiles-utils) |
|||
(require 'pacfiles-win) |
|||
|
|||
(require 'cl-seq) |
|||
(require 'ediff) |
|||
(require 'outline) |
|||
(require 'time-date) |
|||
|
|||
(defgroup pacfiles nil "Faces for the buttons used in pacfiles-mode." |
|||
:group 'tools) |
|||
|
|||
(defvar pacfiles-updates-search-command "find /etc -name '*.pacnew' -o -name '*.pacsave' 2>/dev/null" |
|||
"Command to find .pacnew files.") |
|||
|
|||
(defvar pacfiles--merge-search-command |
|||
(concat "find " pacfiles-merge-file-tmp-location " -name '*.pacmerge' 2>/dev/null") |
|||
"Command to search for temporarily merged files.") |
|||
|
|||
(defvar pacfiles--ediff-conf '() |
|||
"Alist that stores ediff variables and its values.") |
|||
|
|||
|
|||
;;;###autoload |
|||
(defalias 'pacfiles 'pacfiles-start) |
|||
|
|||
;;;###autoload |
|||
(defun pacfiles-start () |
|||
"Find and manage pacman backup files in an Arch-based GNU/Linux system." |
|||
(interactive) |
|||
;; Save the current window configuration so that it can be restored when we are finished. |
|||
(pacfiles--push-window-conf) |
|||
;; Save ediff varaibles that we modify to later restore them to the uers's value. |
|||
(pacfiles--save-ediff-conf) |
|||
(let ((buffer (get-buffer-create pacfiles--files-buffer-name))) |
|||
(display-buffer buffer '(pacfiles--display-buffer-fullscreen)) |
|||
(with-current-buffer buffer |
|||
(pacfiles-mode) |
|||
(pacfiles-revert-buffer t t)))) |
|||
|
|||
(defun pacfiles-quit () |
|||
"Quit ‘pacfiles-mode’ and restore the previous window and ediff configuration." |
|||
(interactive) |
|||
(pacfiles--restore-ediff-conf) |
|||
;; Kill buffers we create which start with '*pacfiles:' |
|||
(kill-matching-buffers "^\\*pacfiles:.*" t t) |
|||
(pacfiles--pop-window-conf)) |
|||
|
|||
;; Main function that displays the contents of the PACFILES buffer. |
|||
(defun pacfiles-revert-buffer (&optional _ignore-auto noconfirm) |
|||
"Populate the ‘pacfiles-mode’ buffer with .pacnew and .pacsave files. |
|||
|
|||
Ignore IGNORE-AUTO but take into account NOCONFIRM." |
|||
(interactive) |
|||
(with-current-buffer (get-buffer-create pacfiles--files-buffer-name) |
|||
(when (or noconfirm |
|||
(y-or-n-p (format "Reload list of backup pacman files? "))) |
|||
(run-hooks 'before-revert-hook) |
|||
;; The actual revert mechanism starts here |
|||
(let ((inhibit-read-only t) |
|||
(files (split-string (shell-command-to-string pacfiles-updates-search-command) "\n" t)) |
|||
(merged-files (split-string (shell-command-to-string pacfiles--merge-search-command) "\n" t)) |
|||
(pacnew-alist (list)) |
|||
(pacsave-alist (list))) |
|||
(delete-region (point-min) (point-max)) |
|||
(insert "* PACFILES MODE" "\n") |
|||
;; Split .pacnew and .pacsave files |
|||
(dolist (file files) |
|||
;; Associate each FILE in FILES with a file to hold the merge |
|||
(let ((merge-file (pacfiles--calculate-merge-file file pacfiles-merge-file-tmp-location))) |
|||
(cond |
|||
((string-match-p ".pacnew" file) |
|||
(push (cons file merge-file) pacnew-alist)) |
|||
((string-match-p ".pacsave" file) |
|||
(push (cons file merge-file) pacsave-alist)) |
|||
(t (user-error (format "Cannot process file %s" file)))))) |
|||
;; --- Process .pacnew files --- |
|||
(insert "\n\n" "** PACNEW files" "\n") |
|||
(insert "\n" "*** pending" "\n") |
|||
;; Display the .pacnew files that need merging |
|||
(pacfiles--insert-pending-files pacnew-alist merged-files) |
|||
(insert "\n" "*** merged" "\n") |
|||
;; Display .pacnew files that have an associated merge file. |
|||
(pacfiles--insert-merged-files pacnew-alist merged-files) |
|||
;; --- Process .pacsave files --- |
|||
(insert "\n\n" "** PACSAVE files" "\n") |
|||
(insert "\n" "*** pending" "\n") |
|||
;; Display the .pacsave files that need merging |
|||
(pacfiles--insert-pending-files pacsave-alist merged-files) |
|||
(insert "\n" "*** merged" "\n") |
|||
(pacfiles--insert-merged-files pacsave-alist merged-files) |
|||
(insert "\n\n") |
|||
(pacfiles--insert-footer-buttons)))) |
|||
(goto-char 0)) |
|||
|
|||
;;;###autoload |
|||
(defun pacfiles-revert-buffer-no-confirm () |
|||
"Revert the pacfiles list buffer without asking for confirmation." |
|||
(interactive) |
|||
(pacfiles-revert-buffer t t)) |
|||
|
|||
(defun pacfiles--insert-pending-files (files-alist merged-files) |
|||
"Insert files in FILES-ALIST if their `cdr' is not in MERGED-FILES. |
|||
|
|||
The FILE-TYPE specifies which type of update file we are processing." |
|||
;; Keep files in FILES-ALIST which don't have a cdr in MERGED-FILES. |
|||
(let ((pending-alist (cl-remove-if (lambda (i) (member (cdr i) merged-files)) files-alist))) |
|||
(if (null pending-alist) |
|||
(insert (propertize "--- no pending files ---\n" 'font-lock-face 'font-lock-comment-face)) |
|||
(dolist (file-pair pending-alist) |
|||
(pacfiles--insert-merge-button file-pair) |
|||
(pacfiles--insert-diff-button (car file-pair)) |
|||
(pacfiles--insert-delete-button file-pair) |
|||
(insert (car file-pair) " ") |
|||
(pacfiles--insert-days-old (car file-pair)) |
|||
(insert "\n"))))) |
|||
|
|||
(defun pacfiles--insert-merged-files (files-alist merged-files) |
|||
"Insert files in FILES-ALIST that have an associated file in MERGED-FILES." |
|||
(let ((merged-alist (cl-remove-if-not (lambda (i) (member (cdr i) merged-files)) files-alist))) |
|||
(if (null merged-alist) |
|||
(insert (propertize "--- no merged files ---\n" 'font-lock-face 'font-lock-comment-face)) |
|||
(dolist (file-pair merged-alist) |
|||
(pacfiles--insert-apply-button file-pair) |
|||
(pacfiles--insert-view-merge-button file-pair) |
|||
(pacfiles--insert-discard-button file-pair) |
|||
(insert (car file-pair) " ") |
|||
;; calculate how many days old is the merged file |
|||
(pacfiles--insert-days-created (cdr file-pair)) |
|||
(insert "\n"))))) |
|||
|
|||
(defun pacfiles--insert-days-old (file) |
|||
"Insert how many days passed between FILE and FILE without its extension. |
|||
|
|||
If REVERSE-ORDER is non-nil, calculate the time difference as |
|||
\(FILE without extension\) - FILE." |
|||
(let* ((base-file (file-name-sans-extension file)) |
|||
(time-base-file |
|||
(time-to-seconds (file-attribute-modification-time (file-attributes base-file)))) |
|||
(time-file |
|||
(time-to-seconds (file-attribute-modification-time (file-attributes file)))) |
|||
(reverse-time (< time-file time-base-file))) |
|||
(when (file-exists-p base-file) |
|||
(insert |
|||
(propertize |
|||
(format "(%.1f %s)" |
|||
(time-to-number-of-days |
|||
(cond (reverse-time (time-subtract time-base-file time-file)) |
|||
(t (time-subtract time-file time-base-file)))) |
|||
(if reverse-time "day[s] old" "day[s] ahead")) |
|||
'font-lock-face 'font-lock-warning-face))))) |
|||
|
|||
(defun pacfiles--insert-days-created (file) |
|||
"Insert the number of days since FILE was created." |
|||
(if (file-exists-p file) |
|||
(let ((time-file (file-attribute-modification-time (file-attributes file)))) |
|||
(insert |
|||
(propertize |
|||
(format "(%.1f day[s] since created)" (time-to-number-of-days (time-since time-file))) |
|||
'font-lock-face 'font-lock-string-face))) |
|||
(error "File '%s' dosn't exist" file))) |
|||
|
|||
(defun pacfiles--save-ediff-conf () |
|||
"Save ediff variables we modify with the user's current values. |
|||
We restore the saved variables after ‘pacfiles-mode’ quits." |
|||
(require 'ediff) |
|||
(let ((vars-to-save |
|||
'(ediff-autostore-merges ediff-keep-variants ediff-window-setup-function |
|||
ediff-before-setup-hook ediff-quit-hook ediff-cleanup-hook ediff-quit-merge-hook |
|||
ediff-quit-hook ediff-split-window-function))) |
|||
(dolist (var vars-to-save) |
|||
(push (pacfiles--var-to-cons var) pacfiles--ediff-conf)))) |
|||
|
|||
(defun pacfiles--change-ediff-conf () |
|||
"Change ediff's configuration variables to fit ‘pacfiles-mode’." |
|||
(setq ediff-autostore-merges nil |
|||
ediff-keep-variants t |
|||
ediff-window-setup-function #'ediff-setup-windows-plain |
|||
ediff-split-window-function #'split-window-horizontally) |
|||
(add-hook 'ediff-before-setup-hook #'pacfiles--push-window-conf) |
|||
(add-hook 'ediff-quit-hook #'pacfiles--pop-window-conf t) |
|||
(add-hook 'ediff-cleanup-hook #'pacfiles--clean-after-ediff) |
|||
(remove-hook 'ediff-quit-merge-hook #'ediff-maybe-save-and-delete-merge) |
|||
(add-hook 'ediff-quit-hook (lambda () (pacfiles-revert-buffer t t)))) |
|||
|
|||
(defun pacfiles--restore-ediff-conf () |
|||
"Restore the ediff variables saved by `pacfiles--save-ediff-conf'." |
|||
(dolist (pair pacfiles--ediff-conf) |
|||
(pacfiles--cons-to-var pair)) |
|||
(setq pacfiles--ediff-conf '())) |
|||
|
|||
(defvar pacfiles-mode-map |
|||
(let ((map (make-sparse-keymap))) |
|||
(define-key map (kbd "q") #'pacfiles-quit) |
|||
(define-key map (kbd "g") #'pacfiles-revert-buffer-no-confirm) |
|||
(define-key map (kbd "r") #'pacfiles-revert-buffer-no-confirm) |
|||
(define-key map (kbd "TAB") #'outline-toggle-children) |
|||
(define-key map (kbd "C-c C-p") #'outline-previous-heading) |
|||
(define-key map (kbd "C-c C-n") #'outline-next-heading) |
|||
(define-key map (kbd "n") #'forward-button) |
|||
(define-key map (kbd "p") #'backward-button) |
|||
map) |
|||
"Keymap for ‘pacfiles-mode’.") |
|||
|
|||
;; Tell emacs that, when creating new buffers, pacfiles-mode should not be used |
|||
;; ... as the major mode. |
|||
(put 'pacfiles-mode 'mode-class 'special) |
|||
|
|||
;;;###autoload |
|||
(define-derived-mode pacfiles-mode outline-mode "pacfiles" |
|||
:syntax-table nil |
|||
:abbrev-table nil |
|||
"Major mode for managing .pacnew and .pacsave files." |
|||
;; If the buffer is not the one we create, do nothing and error out. |
|||
(unless (string= (buffer-name) pacfiles--files-buffer-name) |
|||
(user-error "Use the command `pacfiles' instead of `pacfiles-mode' to start pacfiles-mode")) |
|||
;; The buffer shall not be edited. |
|||
(read-only-mode) |
|||
;; No edits... no undo. |
|||
(buffer-disable-undo) |
|||
;; Disable showing parents locally by letting the mode think it's disabled. |
|||
(setq-local show-paren-mode nil) |
|||
(setq show-trailing-whitespace nil) |
|||
;; Disable lines numbers. |
|||
(when (bound-and-true-p global-linum-mode) |
|||
(linum-mode -1)) |
|||
(when (and (fboundp 'nlinum-mode) |
|||
(bound-and-true-p global-nlinum-mode)) |
|||
(nlinum-mode -1)) |
|||
(when (and (fboundp 'display-line-numbers-mode) |
|||
(bound-and-true-p global-display-line-numbers-mode)) |
|||
(display-line-numbers-mode -1)) |
|||
;; Set the function used when reverting pacfile-mode buffers. |
|||
(setq-local revert-buffer-function #'pacfiles-revert-buffer) |
|||
;; configure ediff |
|||
(pacfiles--change-ediff-conf) |
|||
;; configure outline-mode |
|||
(setq-local outline-blank-line t)) |
|||
|
|||
|
|||
(provide 'pacfiles-mode) |
|||
;;; pacfiles-mode.el ends here |
|||
@ -0,0 +1,36 @@ |
|||
;;; pacfiles-utils.el --- common utilities of pacfiles-mode -*- lexical-binding: t; -*- |
|||
|
|||
;;; Commentary: |
|||
;; Utility functions used throughout pacfiles-mode |
|||
;; |
|||
;;; Code: |
|||
|
|||
(defun pacfiles--calculate-merge-file (file path) |
|||
"File name associated to the merge file tied to FILE located in PATH." |
|||
(concat path (substring (secure-hash 'md5 file) 0 10) ".pacmerge")) |
|||
|
|||
(defun pacfiles--add-sudo-maybe (file-path permission) |
|||
"Add \"/sudo::\" to FILE-PATH if the file does not meet the PERMISSION. |
|||
FILE-PATH is a variable pointing to a file name. |
|||
PERMISSION is either \":read\" or \":write\"" |
|||
(let ((predicate (cond ((eq permission :read) #'file-readable-p) |
|||
((eq permission :write) #'file-writable-p) |
|||
(t (user-error "Unknown keyword")))) |
|||
(apt-path file-path)) |
|||
(unless (funcall predicate apt-path) |
|||
(setq apt-path (concat "/sudo::" apt-path)) |
|||
(unless (funcall predicate apt-path) |
|||
(error "Could not %s \"%s\"" (if (eq permission :read) "read" "write") file-path))) |
|||
apt-path)) |
|||
|
|||
(defun pacfiles--var-to-cons (var) |
|||
"Create a cons of the VAR symbol and the VAR value." |
|||
`(,var . ,(symbol-value var))) |
|||
|
|||
(defun pacfiles--cons-to-var (cons) |
|||
"Set the `car' of CONS to the `cdr' of CONS." |
|||
(let ((var (car cons))) |
|||
(set var (cdr cons)))) |
|||
|
|||
(provide 'pacfiles-utils) |
|||
;;; pacfiles-utils.el ends here |
|||
@ -0,0 +1,84 @@ |
|||
;;; pacfiles-win.el --- Window related functions -*- lexical-binding: t; -*- |
|||
|
|||
;;; Commentary: |
|||
;; Functions to manage the windows of pacfiles-mode |
|||
;; |
|||
;;; Code: |
|||
|
|||
(require 'subr-x) |
|||
(require 'ediff) |
|||
|
|||
(defvar pacfiles--files-buffer-name "*pacfiles:file-list*" |
|||
"Name of the window that holds the list of pacman files.") |
|||
|
|||
(defvar pacfiles-merge-file-tmp-location "/tmp/" |
|||
"Location of temporary merged filed.") |
|||
|
|||
(defvar pacfiles--previous-window-confs '() |
|||
"The window configuration before `pacfiles' is called.") |
|||
|
|||
(defvar pacfiles--empty-buffer-name "*pacfiles:empty-buffer*" |
|||
"Empty buffer meant to replace buffers killed in EDIFF windows. |
|||
Doing this replacement avoids having multiple windows open with the same buffer. |
|||
Having the same buffer open in multiple windows might break the proper killing of |
|||
EDIFF windows.") |
|||
|
|||
(defun pacfiles--display-buffer-fullscreen (buffer alist) |
|||
"Display BUFFER fullscreen taking ALIST into account." |
|||
(when-let (window (or (display-buffer-reuse-window buffer alist) |
|||
(display-buffer-same-window buffer alist) |
|||
(display-buffer-pop-up-window buffer alist) |
|||
(display-buffer-use-some-window buffer alist))) |
|||
(delete-other-windows window) |
|||
window)) |
|||
|
|||
(defun pacfiles--push-window-conf () |
|||
"Push the current window configuration to later be restored by `pacfiles--restore-window-conf'." |
|||
(let ((win-conf (current-window-configuration))) |
|||
(push win-conf pacfiles--previous-window-confs))) |
|||
|
|||
(defun pacfiles--pop-window-conf () |
|||
"Restore the first window configuration found in `pacfiles--previous-window-confs'." |
|||
(if pacfiles--previous-window-confs |
|||
(condition-case nil |
|||
(progn |
|||
(let ((win-conf (pop pacfiles--previous-window-confs))) |
|||
(set-window-configuration win-conf))) |
|||
(error "Window configuration could not be restored")) |
|||
(error "No window configurations to restore"))) |
|||
|
|||
(defun pacfiles--clean-after-ediff () |
|||
"Kill buffers that ediff has left behind. Ask user if merged file is modified." |
|||
(let ((window-a ediff-window-A) |
|||
(window-b ediff-window-B) |
|||
(window-c ediff-window-C) |
|||
(empty-buffer (get-buffer-create pacfiles--empty-buffer-name))) |
|||
;; Save the merged buffer if the user wants and kill it |
|||
(when window-c ; window-c is nil when diffing instead or merging |
|||
(save-excursion |
|||
(select-window window-c t) ; buffer-c is made current |
|||
(when (and (buffer-modified-p) |
|||
(y-or-n-p (format "'%s' was modified. Save before killing? " (buffer-name)))) |
|||
(save-buffer)) |
|||
(set-buffer-modified-p nil) ; Set buffer to not modified to not ask user |
|||
(kill-buffer) |
|||
(switch-to-buffer empty-buffer))) ;; Kill file-a and file-b always. We want to explicitly set the current buffer |
|||
;; ... to make sure that no function in `kill-buffer-query-functions' stops us. |
|||
(save-excursion |
|||
(select-window window-a t) ; this makes buffer-a current |
|||
(switch-to-buffer empty-buffer)) |
|||
(save-excursion |
|||
(select-window window-b t) ; this makes buffer-b current |
|||
(switch-to-buffer empty-buffer)))) |
|||
|
|||
(defun pacfiles--create-view-buffer (name file) |
|||
"Show FILE in a new buffer named NAME that pacfiles will manage." |
|||
(let ((view-buffer |
|||
(get-buffer-create (concat "*pacfiles:merge-" name "*")))) |
|||
(with-current-buffer view-buffer |
|||
(insert-file-contents file nil nil nil t) |
|||
(read-only-mode) |
|||
view-buffer))) |
|||
|
|||
(provide 'pacfiles-win) |
|||
;;; pacfiles-win.el ends here |
|||
@ -0,0 +1 @@ |
|||
Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasign@elpa.gnu.org> (trust undefined) created at 2019-09-21T12:58:29-0500 using RSA |
|||
@ -0,0 +1,29 @@ |
|||
;;; sed-mode-autoloads.el --- automatically extracted autoloads |
|||
;; |
|||
;;; Code: |
|||
|
|||
(add-to-list 'load-path (directory-file-name |
|||
(or (file-name-directory #$) (car load-path)))) |
|||
|
|||
|
|||
;;;### (autoloads nil "sed-mode" "sed-mode.el" (0 0 0 0)) |
|||
;;; Generated autoloads from sed-mode.el |
|||
(add-to-list 'auto-mode-alist '("\\.sed\\'" . sed-mode)) |
|||
(add-to-list 'interpreter-mode-alist '("sed" . sed-mode)) |
|||
|
|||
(autoload 'sed-mode "sed-mode" "\ |
|||
Sed editing mode. |
|||
|
|||
\(fn)" t nil) |
|||
|
|||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "sed-mode" '("sed-"))) |
|||
|
|||
;;;*** |
|||
|
|||
;; Local Variables: |
|||
;; version-control: never |
|||
;; no-byte-compile: t |
|||
;; no-update-autoloads: t |
|||
;; coding: utf-8 |
|||
;; End: |
|||
;;; sed-mode-autoloads.el ends here |
|||
@ -0,0 +1,2 @@ |
|||
;;; Generated package description from sed-mode.el -*- no-byte-compile: t -*- |
|||
(define-package "sed-mode" "1.0" "Major mode to edit sed scripts" 'nil :url "http://elpa.gnu.org/packages/sed-mode.html" :authors '(("Stefan Monnier" . "monnier@iro.umontreal.ca")) :maintainer '("Stefan Monnier" . "monnier@iro.umontreal.ca")) |
|||
@ -0,0 +1,154 @@ |
|||
;;; sed-mode.el --- Major mode to edit sed scripts -*- lexical-binding: t; -*- |
|||
|
|||
;; Copyright (C) 2016 Free Software Foundation, Inc. |
|||
|
|||
;; Author: Stefan Monnier <monnier@iro.umontreal.ca> |
|||
;; Version: 1.0 |
|||
;; Keywords: |
|||
|
|||
;; This program is free software; you can redistribute it and/or modify |
|||
;; it under the terms of the GNU General Public License as published by |
|||
;; the Free Software Foundation, either version 3 of the License, or |
|||
;; (at your option) any later version. |
|||
|
|||
;; This program is distributed in the hope that it will be useful, |
|||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
;; GNU General Public License for more details. |
|||
|
|||
;; You should have received a copy of the GNU General Public License |
|||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
;;; Commentary: |
|||
|
|||
;; If you need this major mode, you might also want to |
|||
;; consider spending some time with `M-x doctor'. |
|||
|
|||
;;; Code: |
|||
|
|||
(require 'cl-lib) |
|||
(require 'smie) |
|||
|
|||
(defgroup sed-mode nil |
|||
"Major mode to edit sed code." |
|||
:group 'programming) |
|||
|
|||
|
|||
(defvar sed-mode-syntax-table |
|||
(let ((st (make-syntax-table))) |
|||
(modify-syntax-entry ?# "<" st) |
|||
(modify-syntax-entry ?\n ">" st) |
|||
(modify-syntax-entry ?\\ "." st) |
|||
st)) |
|||
|
|||
(defconst sed-commands ":=aiqQrRbcdDhHgGlnNpPstTwWxy") |
|||
|
|||
(eval-and-compile |
|||
(defconst sed-command-prefix-regexp "\\(?:^\\|[$/0-9;]\\)[ \t]*") |
|||
(defconst sed-address-prefix-regexp "\\(?:^\\|[,;]\\)[ \t]*")) |
|||
|
|||
(defconst sed-label-regexp "[[:alnum:]]+") |
|||
|
|||
(defun sed-syntax-propertize (beg end) |
|||
(goto-char beg) |
|||
(sed-syntax-propertize-string end) |
|||
(funcall |
|||
(syntax-propertize-rules |
|||
("\\\\$" |
|||
(0 (unless (nth 8 (save-excursion (syntax-ppss (match-beginning 0)))) |
|||
(put-text-property (match-beginning 0) (match-end 0) |
|||
'syntax-table (string-to-syntax "|")) |
|||
(sed-syntax-propertize-string end) |
|||
nil))) |
|||
((concat "\\(?:" sed-address-prefix-regexp |
|||
"\\(?:\\(?1:/\\)\\|\\\\\\(?1:.\\)\\)" |
|||
"\\|" sed-command-prefix-regexp "[sy]\\(?1:.\\)" |
|||
"\\)") |
|||
(0 (unless (nth 8 (save-excursion (syntax-ppss (match-beginning 0)))) |
|||
(put-text-property (match-beginning 1) (match-end 1) |
|||
'syntax-table (string-to-syntax "\"")) |
|||
(sed-syntax-propertize-string end) |
|||
nil)))) |
|||
(point) end)) |
|||
|
|||
(defun sed-syntax-propertize-string (end) |
|||
(let* ((ppss (syntax-ppss)) |
|||
(c (nth 3 ppss))) |
|||
(when c |
|||
(let ((count (cond |
|||
((or (eq c t) |
|||
(not (memq (char-before (nth 8 ppss)) '(?s ?y)))) |
|||
1) |
|||
(t 2)))) |
|||
(goto-char (1+ (nth 8 ppss))) |
|||
(when (re-search-forward |
|||
(if (eq c t) "[^\\]\n" (regexp-quote (string c))) |
|||
end 'move count) |
|||
(put-text-property (1- (match-end 0)) (match-end 0) |
|||
'syntax-table |
|||
(if (eq c t) (string-to-syntax "|") |
|||
(string-to-syntax "\"")))))))) |
|||
|
|||
(defun sed--font-lock-command (cmd) |
|||
(unless (nth 8 (syntax-ppss)) |
|||
(pcase cmd |
|||
(?: (if (looking-at (concat "[ ]*\\(" sed-label-regexp "\\)")) |
|||
(put-text-property (match-beginning 1) (match-end 1) 'face |
|||
font-lock-function-name-face))) |
|||
((or ?b ?t ?T) |
|||
(if (looking-at (concat "[ ]*\\(" sed-label-regexp "\\)")) |
|||
(put-text-property (match-beginning 1) (match-end 1) 'face |
|||
font-lock-constant-face)))) |
|||
font-lock-keyword-face)) |
|||
|
|||
(defconst sed-font-lock-keywords |
|||
`((,(concat sed-command-prefix-regexp "\\([" sed-commands "]\\)") |
|||
(1 (sed--font-lock-command (char-after (match-beginning 1))))))) |
|||
|
|||
(defconst sed-smie-grammar nil) |
|||
|
|||
(defun sed-smie-rules (kind token) |
|||
(pcase (cons kind token) |
|||
(`(:list-intro . ,_) t) |
|||
)) |
|||
|
|||
;;;###autoload (add-to-list 'auto-mode-alist '("\\.sed\\'" . sed-mode)) |
|||
;;;###autoload (add-to-list 'interpreter-mode-alist '("sed" . sed-mode)) |
|||
|
|||
;;;###autoload |
|||
(define-derived-mode sed-mode prog-mode "Sed" |
|||
"Sed editing mode." |
|||
;; (setq-local font-lock-support-mode nil) ;; To help debugging. |
|||
(setq-local comment-start "# ") |
|||
(setq-local comment-end "") |
|||
(setq-local parse-sexp-lookup-properties t) |
|||
(setq-local open-paren-in-column-0-is-defun-start nil) |
|||
(setq-local syntax-propertize-function #'sed-syntax-propertize) |
|||
(setq-local font-lock-defaults '(sed-font-lock-keywords)) |
|||
(smie-setup sed-smie-grammar #'sed-smie-rules |
|||
;; :backward-token #'sm-c-smie-backward-token |
|||
;; :forward-token #'sm-c-smie-forward-token |
|||
) |
|||
;; Backslash auto-realign. |
|||
;; (add-hook 'after-change-functions #'sm-c--bs-after-change nil t) |
|||
;; (add-hook 'post-command-hook #'sm-c--bs-realign nil t) |
|||
;; (setq-local add-log-current-defun-header-regexp sm-c--def-regexp) |
|||
;; (setq-local imenu-generic-expression `((nil ,sm-c--def-regexp 1))) |
|||
) |
|||
|
|||
;;;; ChangeLog: |
|||
|
|||
;; 2016-02-26 Stefan Monnier <monnier@iro.umontreal.ca> |
|||
;; |
|||
;; * sed-mode/sed-mode.el: Bump up version for first release |
|||
;; |
|||
;; (interpreter-mode-alist): Register ourselves. |
|||
;; |
|||
;; 2016-02-25 Stefan Monnier <monnier@iro.umontreal.ca> |
|||
;; |
|||
;; * sed-mode: New package |
|||
;; |
|||
|
|||
|
|||
(provide 'sed-mode) |
|||
;;; sed-mode.el ends here |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue