diff --git a/TODO.org b/TODO.org index dc04cfcd1..4d19d1046 100644 --- a/TODO.org +++ b/TODO.org @@ -89,7 +89,7 @@ + [ ] twitter + [ ] present -** 2.0.3 [22/42] +** 2.0.3 [23/46] + [ ] Test ~package-autoremove~ + [ ] tools/upload: add ~+upload/open-remote-file~ command to open current file on the remote (with TRAMP) @@ -104,16 +104,21 @@ + [ ] Write ~describe-setting~ for ~def-setting!~ definitions. + [ ] Fix invisible buffer-info segment in modeline for terminal Emacs + [ ] ui/doom-modeline: fix ~0/0~ display in modeline (leftover anzu state) -+ [1/9] New module :: tools/regex (PCRE IDE) ++ [2/13] New module :: tools/regex (PCRE IDE) + [X] perl backend - + [ ] replace support - + [ ] export to code support - + [ ] python exporter (use ~re~ or ~regex~) - + [ ] php exporter (~preg_(match(_all)?|replace)~) - + [ ] ruby backend (~%r[.+]~) - + [ ] javascript (node) backend (~/.+/~) + + [X] replace support + + [-] highlight replaced segments + + [0/7] export-to-code feature + + [ ] search+replace support + + [ ] python exporter (use ~re~ or ~regex~) + + [ ] php exporter (~preg_(match(_all)?|replace)~) + + [ ] ruby exporter (~%r[.+]~) + + [ ] javascript (node) exporter (~/.+/.test(...)~) + + [ ] C exporter (~regex.h~ + ~regcomp~) + + [ ] C++ exporter (~regex reg(regexp, ...)~) + [ ] syntax highlighter for ~+regex-mode~ (plus make it a major mode) + [ ] README.org + + [ ] Use ~make-process~ daemon approach rather than ~call-process~ + [X] ui/doom: fix nav-flash on evil-multiedit or in eshell/term buffers + [X] core-os: don't use GTK tooltips (ugly!) + [X] ui/doom-modeline: reduce excess whitespace on right of flycheck segment diff --git a/modules/app/regex/autoload/regex.el b/modules/app/regex/autoload/regex.el index b6912802c..0a994c26a 100644 --- a/modules/app/regex/autoload/regex.el +++ b/modules/app/regex/autoload/regex.el @@ -1,22 +1,25 @@ ;;; app/regex/autoload/regex.el (defvar +regex--text-buffer nil) +(defvar +regex--text-replace-buffer nil) (defvar +regex--expr-buffer nil) +(defvar +regex--expr-replace-buffer nil) (defvar +regex--groups-buffer nil) +(defvar +regex--replace-buffer nil) ;; (defface +regex-match-0-face - '((t (:foreground "Black" :background "Red" :bold t))) + `((t (:foreground "Black" :background ,(doom-color 'magenta) :bold t))) "TODO" :group 'doom) (defface +regex-match-1-face - '((t (:foreground "Black" :background "Blue" :bold t))) + `((t (:foreground "Black" :background ,(doom-color 'blue) :bold t))) "TODO" :group 'doom) (defface +regex-match-2-face - '((t (:foreground "Black" :background "Green" :bold t))) + `((t (:foreground "Black" :background ,(doom-color 'green) :bold t))) "TODO" :group 'doom) @@ -27,9 +30,13 @@ ;; (defvar +regex-mode-map (let ((map (make-sparse-keymap))) - (evil-define-key* 'normal map - "\C-c\C-c" #'+regex-update-buffers - "\C-c\C-k" #'+regex/quit) + (define-key map "\C-c\C-c" #'+regex-update-buffers) + (define-key map "\C-c\C-r" #'=regex/replace) + (define-key map "\C-c\C-k" #'+regex/quit) + (define-key map [remap doom-kill-buffer] #'+regex/quit) + (define-key map [remap doom/kill-this-buffer] #'+regex/quit) + (define-key map [remap kill-this-buffer] #'+regex/quit) + (define-key map [remap kill-buffer] #'+regex/quit) map) "TODO") @@ -48,75 +55,119 @@ (defun =regex (&optional dummy-text) "Start the Regex IDE." (interactive "P") - (condition-case ex - (progn - (setq +regex--expr-buffer (get-buffer-create "*doom-regex*") - +regex--text-buffer (if dummy-text (get-buffer-create "*doom-regex-text*") (current-buffer)) - +regex--groups-buffer (get-buffer-create "*doom-regex-groups*")) - (when dummy-text - (+workspace-switch +regex-workspace-name t) - (switch-to-buffer +regex--text-buffer) - (insert +regex-dummy-text)) - (doom-popup-buffer +regex--groups-buffer) - (doom-popup-buffer +regex--expr-buffer) - (with-current-buffer +regex--expr-buffer - (conf-mode) - (rainbow-delimiters-mode +1) - (linum-mode -1) - (+regex-mode +1) - (text-scale-set 3))) - ('error - (+regex/quit) - (error "Failed to open the Regexp IDE: %s" ex)))) + (unless (buffer-live-p +regex--expr-buffer) + (condition-case ex + (progn + (setq +regex--expr-buffer (get-buffer-create "*doom-regex*") + +regex--text-buffer (if dummy-text (get-buffer-create "*doom-regex-text*") (current-buffer)) + +regex--groups-buffer (get-buffer-create "*doom-regex-groups*")) + (when dummy-text + (+workspace-switch +regex-workspace-name t) + (switch-to-buffer +regex--text-buffer) + (with-current-buffer +regex--text-buffer + (insert +regex-dummy-text))) + (doom-popup-buffer +regex--groups-buffer) + (doom-popup-buffer +regex--expr-buffer) + (with-current-buffer +regex--expr-buffer + (conf-mode) + (rainbow-delimiters-mode +1) + (linum-mode -1) + (setq-local require-final-newline nil) + (+regex-mode +1) + (text-scale-set 3))) + ('error + (+regex/quit) + (error "Failed to open the Regexp IDE: %s" ex))))) + +;;;###autoload +(defun =regex/replace () + (interactive) + (unless (buffer-live-p +regex--replace-buffer) + (let (text) + (=regex t) + (with-selected-window (get-buffer-window +regex--text-buffer) + (setq text (buffer-string)) + (select-window (split-window-right)) + (switch-to-buffer (get-buffer-create "*doom-regex-text-repl*")) + (erase-buffer) + (insert text) + (read-only-mode +1) + (setq +regex--text-replace-buffer (current-buffer))) + (with-current-buffer +regex--expr-buffer + (select-window (split-window-right)) + (switch-to-buffer (get-buffer-create "*doom-regex-repl*")) + (conf-mode) + (rainbow-delimiters-mode +1) + (linum-mode -1) + (setq-local require-final-newline nil) + (setq mode-line-format nil + +regex--expr-replace-buffer (current-buffer)) + (+regex-mode +1) + (text-scale-set 3))))) ;;;###autoload (defun +regex/quit () "TODO" (interactive) - (kill-buffer +regex--expr-buffer) - (kill-buffer +regex--groups-buffer) (when (and +regex--text-buffer (buffer-live-p +regex--text-buffer)) (with-current-buffer +regex--text-buffer (+regex-mode -1) - (remove-overlays))) - (setq +regex--expr-buffer nil - +regex--text-buffer nil - +regex--groups-buffer nil) + (remove-overlays nil nil 'category '+regex)) + (when (equal (buffer-name +regex--text-buffer) "*doom-regex-text*") + (kill-buffer +regex--text-buffer))) (when (equal (+workspace-current-name) +regex-workspace-name) - (kill-buffer +regex--text-buffer) - (+workspace/delete +regex-workspace-name))) + (+workspace/delete +regex-workspace-name)) + (mapc (lambda (bufname) + (let ((buf (symbol-value bufname))) + (when (and buf (buffer-live-p buf)) + (kill-buffer buf) + (set bufname nil)))) + (list '+regex--text-replace-buffer + '+regex--expr-replace-buffer + '+regex--expr-buffer + '+regex--groups-buffer + '+regex--replace-buffer))) + +(defun +regex--expr () + (when (buffer-live-p +regex--expr-buffer) + (with-current-buffer +regex--expr-buffer + (string-trim (buffer-string))))) + +(defun +regex--expr-replace () + (when (buffer-live-p +regex--expr-replace-buffer) + (with-current-buffer +regex--expr-replace-buffer + (string-trim (buffer-string))))) ;;;###autoload (defun +regex-update-buffers (&optional beg end len) (interactive) - (let ((regex (with-current-buffer +regex--expr-buffer (buffer-string)))) - (when (> (length regex) 0) - (with-current-buffer +regex--groups-buffer - (erase-buffer)) - (with-current-buffer +regex--text-buffer - (remove-overlays) + (let* ((inhibit-read-only t) + (regex (or (+regex--expr) "")) + (replace (or (+regex--expr-replace) "")) + (str (or (with-current-buffer +regex--text-buffer (buffer-string)) ""))) + (with-current-buffer +regex--groups-buffer + (erase-buffer)) + (with-current-buffer +regex--text-buffer + (remove-overlays nil nil 'category '+regex) + (when (> (length regex) 0) (save-excursion - (ignore-errors - (goto-char (point-min)) - (pcase +regex-default-backend - ('emacs (+regex-backend-emacs regex)) - ('perl (+regex-backend-generic (+regex-backend-perl regex))) - ('python (+regex-backend-generic (+regex-backend-python regex))))))) - (with-current-buffer +regex--groups-buffer - (goto-char (point-min)))))) + (goto-char (point-min)) + (pcase +regex-default-backend + ('emacs (+regex-backend-emacs regex replace str)) + ('perl (+regex-backend-perl regex replace str)))))) + (with-current-buffer +regex--groups-buffer + (goto-char (point-min))))) ;; --- backends --------------------------- -(defun +regex--backend-perl (regex sample) +(defun +regex--render-perl (regex text) "From " (with-temp-buffer - (unless (string-match-p "^/.+/[gm]*$" regex) - (setq regex (concat "/" regex "/g"))) (insert (format "@lines = ; $line = join(\"\", @lines); print \"(\"; -while ($line =~ m%smg) { +while ($line =~ m/%s/gm) { print \"(\", length($`), \" \", length($&), \" \"; for $i (1 .. 20) { if ($$i) { @@ -129,53 +180,95 @@ while ($line =~ m%smg) { } print \")\"; __DATA__ -%s" regex sample)) +%s" (replace-regexp-in-string "/" "\\/" regex nil t) text)) (call-process-region (point-min) (point-max) "perl" t t) (goto-char (point-min)) (read (current-buffer)))) +(defun +regex--replace-perl (regex replace text) + (unless (or (string-empty-p regex) + (string-empty-p replace) + (string-empty-p text)) + (with-temp-buffer + (insert (format "@lines = ; +$line = join(\"\", @lines); +$line =~ s/%s/%s/gm; +print $line; +__DATA__ +%s" (replace-regexp-in-string "/" "\\/" regex nil t) (replace-regexp-in-string "/" "\\/" replace nil t) text)) + (call-process-region (point-min) (point-max) "perl" t t) + (buffer-string)))) + ;;;###autoload -(defun +regex-backend-perl (regex) +(defun +regex-backend-perl (regex replace str) "TODO" - (let ((results (+regex--render-perl regex (buffer-string))) - (i 0)) - (dolist (result results) - (let ((offset (nth 0 result)) - (length (nth 1 result)) - (matches (nthcdr 2 result))) - (overlay-put (make-overlay (1+ offset) (+ offset length 1)) - 'face (nth (mod i 3) +regex-faces)) + (cl-assert (stringp regex)) + (cl-assert (stringp replace)) + (cl-assert (stringp str)) + (let ((i 0) + (results (+regex--render-perl regex str))) + (when (buffer-live-p +regex--text-replace-buffer) + (let ((replace (+regex--replace-perl regex replace str))) + (with-current-buffer +regex--text-replace-buffer + (erase-buffer) + (insert + (if (and (listp results) + replace + (not (string-empty-p replace))) + replace + str))))) + (dolist (result (if (listp results) results)) + (let* ((offset (nth 0 result)) + (length (nth 1 result)) + (matches (nthcdr 2 result)) + (ov (make-overlay (1+ offset) (+ offset length 1)))) + (overlay-put ov 'face (nth (mod i 3) +regex-faces)) + (overlay-put ov 'category '+regex) (cl-incf i) - (let ((match-zero (buffer-substring (1+ offset) (+ offset length 1)))) + (let* ((match-zero (buffer-substring (1+ offset) (+ offset length 1))) + (line (format "Match: %s\n" (propertize match-zero 'face 'font-lock-string-face)))) (with-current-buffer +regex--groups-buffer - (insert (format "Group 0: '%s'\n" match-zero)))) + (insert line))) (dolist (match matches) (with-current-buffer +regex--groups-buffer (goto-char (point-max)) - (insert (format "Group %d: '%s'\n" (car match) - (cdr match))))) + (insert (format "Group %d: %s\n" + (propertize (car match) 'face 'font-lock-constant-face) + (propertize (cdr match) 'face 'font-lock-string-face))))) (with-current-buffer +regex--groups-buffer (insert ?\n)))))) ;;;###autoload -(defun +regex-backend-emacs (regex) +(defun +regex-backend-emacs (regex replace str) "TODO" + (cl-assert (stringp regex)) + (cl-assert (stringp replace)) + (cl-assert (stringp str)) (let ((i 0) pos) + (when (buffer-live-p +regex--text-replace-buffer) + (with-current-buffer +regex--text-replace-buffer + (erase-buffer) + (insert str) + (when (and (listp results) (string-empty-p replace)) + (replace-regexp regex replace)))) (while (and (setq pos (point)) (re-search-forward regex nil t)) (if (= (point) pos) (forward-char 1) - (overlay-put (make-overlay (match-beginning 0) - (match-end 0)) - 'face (nth (mod i 3) +regex-faces)) + (let ((ov (make-overlay (match-beginning 0) (match-end 0)))) + (overlay-put ov 'face (nth (mod i 3) +regex-faces)) + (overlay-put ov 'category '+regex)) (cl-incf i) (dotimes (i 10) (when-let (text (match-string i)) (save-match-data (with-current-buffer +regex--groups-buffer (goto-char (point-max)) - (insert (format "Group %d: '%s'\n" i text)))))) + (insert + (format "Group %d: %s\n" + (propertize i 'face 'font-lock-constant-face) + (propertize text 'face 'font-lock-string-face))))))) (with-current-buffer +regex--groups-buffer (insert ?\n)))))) diff --git a/modules/app/regex/config.el b/modules/app/regex/config.el index 17ab21474..cc073013b 100644 --- a/modules/app/regex/config.el +++ b/modules/app/regex/config.el @@ -47,6 +47,6 @@ https://mediatemple.net" "TODO") (set! :popup - '("*doom-regex*" :size 4 :select t :noesc t :autokill t) - '("*doom-regex-groups*" :align left :size 30 :noselect t :noesc t :autokill t)) + '("*doom-regex*" :size 4 :select t :noesc t) + '("*doom-regex-groups*" :align left :size 30 :noselect t :noesc t))