emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/shellcop 38cfb38a2b 01/10: first import


From: ELPA Syncer
Subject: [nongnu] elpa/shellcop 38cfb38a2b 01/10: first import
Date: Wed, 5 Jan 2022 08:59:34 -0500 (EST)

branch: elpa/shellcop
commit 38cfb38a2b2ddf25d388310caf2b4ba2aa3df677
Author: Chen Bin <chenbin.sh@gmail.com>
Commit: Chen Bin <chenbin.sh@gmail.com>

    first import
---
 .gitignore  |  26 +++++
 README.org  |  33 +++++++
 demo.png    | Bin 0 -> 91875 bytes
 shellcop.el | 308 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 367 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..208721001a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+### /Users/cb/.gitignore-boilerplates/Global/Emacs.gitignore
+
+*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+.elc
+auto-save-list
+tramp
+.\#*
+
+# Org-mode
+.org-id-locations
+*_archive
+
+
+### /Users/cb/.gitignore-boilerplates/Global/Vim.gitignore
+
+.*.sw[a-z]
+*.un~
+Session.vim
+.netrwhist
+
+*.tar
+*.elc
+
diff --git a/README.org b/README.org
new file mode 100644
index 0000000000..5e6dc74e8f
--- /dev/null
+++ b/README.org
@@ -0,0 +1,33 @@
+* shellcop
+[[https://travis-ci.org/redguardtoo/shellcop][https://travis-ci.org/redguardtoo/shellcop.svg?branch=master]]
+[[http://melpa.org/#/shellcop][file:http://melpa.org/packages/shellcop-badge.svg]]
+[[http://stable.melpa.org/#/shellcop][file:http://stable.melpa.org/packages/shellcop-badge.svg]]
+
+Analyze errors reported in Emacs builtin shell.
+
+* Install
+shellcop is already uploaded to [[http://melpa.org]]. The best way to install 
is Emacs package manager.
+* Usage
+Insert below code into =~/.emacs=,
+#+begin_src elisp
+(add-hook 'shell-mode-hook 'shellcop-start)
+#+end_src
+
+Run any command line program in shell. Move the focus inside the error report 
of command line program.
+
+Press =Enter= key. The file path and line number information is extracted and 
you can open corresponding file.
+
+[[file:demo.png]]
+
+Run =shellcop-erase-buffer= to erase following buffers with below names,
+- =*Messages= (default)
+- =*shell*= (if parameter 1 is passed)
+- =*Javascript REPL*= (if parameter 2 is passed)
+- =*eshell*= (if parameter 3 is passed)
+
+Run =shellcop-reset-with-new-command= to,
+- kill current running process
+- erase the content in shell buffer
+- If =shellcop-sub-window-has-error-function= return nil in all sub-windows, 
run =shellcop-insert-shell-command-function=
+* Contact me
+Report bug at [[https://github.com/redguardtoo/shellcop]].
diff --git a/demo.png b/demo.png
new file mode 100644
index 0000000000..dc9349783a
Binary files /dev/null and b/demo.png differ
diff --git a/shellcop.el b/shellcop.el
new file mode 100644
index 0000000000..41a9ba43a3
--- /dev/null
+++ b/shellcop.el
@@ -0,0 +1,308 @@
+;;; shellcop.el --- analyze errors reported in Emacs builtin shell  -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2020 Chen Bin
+;;
+;; Version: 0.0.1
+;; Keywords: unix tools
+;; Author: Chen Bin <chenbin DOT sh AT gmail DOT com>
+;; URL: https://github.com/redguardtoo/shellcop
+;; Package-Requires: ((emacs "25.1"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; 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, 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 <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;  Open the file from command line error report,
+;;   - Insert "(with-eval-after-load 'shell-mode 'shellcop-start)" into 
~/.emacs
+;;   - Start shell by "M-x shell"
+;;   - Run any command line program in shell
+;;   - Press ENTER in command line program error output which contains file 
and line number
+;;
+;; `shellcop-reset-with-new-command' will,
+;;   - kill current running process
+;;   - erase the content in shell buffer
+;;   - If `shellcop-sub-window-has-error-function' return nil in all 
sub-windows, run `shellcop-insert-shell-command-function'
+;;
+;; `shellcop-erase-buffer' erases the content buffer with below names,
+;;   - "*Messages*" (default)
+;;   - "*shell*" (if parameter 1 is passed)
+;;   - "*Javascript REPL*" (if parameter 2 is passed)
+;;   - "*eshell*" (if parameter 3 is passed)
+;;
+
+;;; Code:
+
+;;;
+
+(require 'cl-lib)
+
+(defgroup shellcop nil
+  "Analyze errors reported in Emacs builtin shell."
+  :group 'tools)
+
+(defcustom shellcop-insert-shell-command-function
+  nil
+  "Function to insert command when calling `shellcop-reset-with-new-command'."
+  :type 'function
+  :group 'shellcop)
+
+(defcustom shellcop-sub-window-has-error-function
+  nil
+  "Get errors of sub-window when calling `shellcop-reset-with-new-command'.
+If there is error, it returns t."
+  :type 'function
+  :group 'shellcop)
+
+(defcustom shellcop-excluded-file-patterns
+  '("\\.\\(bundle\\|min\\)\\.[tj]sx?$"
+    "/node_modules/"
+    "/\\.svn/"
+    "/\\.hg/"
+    "/\\.git/")
+  "File patterns to be excluded from analysis."
+  :type '(repeat sexp)
+  :group 'shellcop)
+
+(defcustom shellcop-terminal-primary-prompt "^\\$ "
+  "The primary prompt of terminal."
+  :type 'string
+  :group 'shellcop)
+
+(defun shellcop-location-detail (str)
+  "Get file, line and column from STR."
+  (when (string-match "^\\([^:]+\\):\\([0-9]+\\)+\\(:[0-9]+\\)?$" str)
+    (let* ((file (match-string 1 str))
+           (line (match-string 2 str))
+           (col (match-string 3 str)))
+      ;; clean the column format
+      (when col
+        (setq col (replace-regexp-in-string ":" "" col)))
+      (list file line col))))
+
+(defun shellcop-extract-location ()
+  "Extract location from current line."
+  (let* (file
+         (end (line-end-position))
+         rlt)
+    (save-excursion
+      (goto-char (line-beginning-position))
+
+      ;; return the first found
+      (while (and (< (point) end) (not rlt))
+        ;; searching
+        (when (setq file (thing-at-point 'filename))
+          (when (setq rlt (shellcop-location-detail file))
+            (setq rlt (cons (string-trim (shellcop-current-line)) rlt))))
+        (forward-word)))
+    rlt))
+
+(defmacro shellcop-push-location (location result)
+  "Push LOCATION into RESULT."
+  `(unless (cl-some (lambda (pattern)
+                      (let* ((file (nth 1 ,location)))
+                        (or (string-match pattern file)
+                            (not (file-exists-p file)))))
+                    shellcop-excluded-file-patterns)
+     (push ,location ,result)))
+
+(defun shellcop-extract-locations-at-point (&optional above)
+  "Extract locations in one direction into RLT.
+If ABOVE is t, extract locations above current point; or else below current 
point."
+  (let* (rlt
+         (line (if above -1 1))
+         location)
+    (save-excursion
+      (while (and (eq (forward-line line) 0)
+                  (setq location (shellcop-extract-location)))
+        (shellcop-push-location location rlt)))
+    rlt))
+
+(defun shellcop-extract-all-locations ()
+  "Extract all locations near current point."
+  (let* ((location (shellcop-extract-location))
+         rlt)
+    ;; at least current line should contain file path
+    (when location
+      (shellcop-push-location location rlt)
+      (setq rlt (append rlt
+                        (shellcop-extract-locations-at-point t)
+                        (shellcop-extract-locations-at-point))))
+    rlt))
+
+(defun shellcop-forward-line (n)
+  "Forward N lines."
+  (when (and n (> n 0))
+    (goto-char (point-min))
+    (forward-line (1- n))))
+
+(defun shellcop-comint-send-input-hack (orig-func &rest args)
+  "Advice `comint-send-input' with ORIG-FUNC and ARGS."
+  (let* ((artifical (nth 1 args))
+         locations)
+    (cond
+     ((or artifical (not (eq major-mode 'shell-mode)))
+      ;; do nothing
+      (apply orig-func args))
+
+     ((setq locations (shellcop-extract-all-locations))
+      (let* (location-detail
+             location)
+        (when (and (> (length locations) 0)
+                   (setq location (completing-read "Go to: " locations))
+                   (setq location-detail (assoc location locations)))
+          (find-file-other-window (nth 1 location-detail))
+          (goto-char (point-min))
+          ;; forward N lines
+          (shellcop-forward-line (string-to-number (nth 2 location-detail)))
+          ;; move to specific column
+          (when (nth 3 location-detail)
+            (goto-char (line-beginning-position))
+            (forward-char (string-to-number (nth 3 location-detail)))))))
+     (t
+      (apply orig-func args)))))
+
+;;;###autoload
+(defun shellcop-start ()
+  "Start this program."
+  (interactive)
+  (advice-add 'comint-send-input :around #'shellcop-comint-send-input-hack))
+
+;;;###autoload
+(defun shellcop-all-windows ()
+  "Return all windows."
+  (cl-mapcan (lambda (f)
+               (window-list f 0 (frame-first-window f)))
+             (visible-frame-list)))
+
+;;;###autoload
+(defun shellcop-current-line ()
+  "Get current line text."
+  (let* ((inhibit-field-text-motion t))
+    (buffer-substring-no-properties (line-beginning-position)
+                                    (line-end-position))))
+
+;;;###autoload
+(defun shellcop-prompt-line-p (&optional position)
+  "If line at POSITION has prompt at the beginning."
+  (let* (rlt)
+    ;; user can't move the cursor to the first column in prompt line
+    (save-excursion
+      (goto-char (or position (point)))
+      (goto-char (line-beginning-position))
+      (setq rlt (> (current-column) 1)))
+
+    ;; another round if we can't decide cursor movement
+    (unless rlt
+      (setq rlt (string-match-p shellcop-terminal-primary-prompt
+                                (shellcop-current-line))))
+    rlt))
+
+(defun shellcop-search-backward-prompt (n)
+  "Search backward for N prompt.
+Return the line beginning of prompt line."
+  (let* (rlt
+         (first-line-end-pos (save-excursion
+                               (goto-char (point-min))
+                               (line-end-position))))
+    (save-excursion
+      (while (and (> (line-beginning-position) first-line-end-pos)
+                  (> n 0))
+        (when (shellcop-prompt-line-p)
+          (setq n (1- n))
+          (setq rlt (line-beginning-position)))
+        (forward-line -1)))
+    rlt))
+
+;;;###autoload
+(defun shellcop-erase-one-visible-buffer (buf-name &optional n)
+  "Erase the content of visible buffer with BUF-NAME.
+Keep latest N cli program output if it's not nil."
+  (let* ((original-window (get-buffer-window))
+         (target-window (get-buffer-window buf-name))
+         beg)
+    (cond
+     ((not target-window)
+      (message "Buffer %s is not visible!" buf-name))
+     (t
+      (select-window target-window)
+      (let* ((inhibit-read-only t))
+        (when (and n (> n 0))
+          ;; skip current prompt line
+          (forward-line -2)
+          (setq beg (shellcop-search-backward-prompt n)))
+        (cond
+         (beg
+          (delete-region (point-min) beg))
+         (t
+          (erase-buffer))))
+      (select-window original-window)))))
+
+;;;###autoload
+(defun shellcop-reset-with-new-command ()
+  "Kill running sub-process, erase shell, insert new command."
+  (interactive)
+  (cond
+   ;; erase buffer, check errors in other window and insert certain command
+   ((derived-mode-p 'comint-mode)
+    ;; loop all sub-windows.
+    ;; if no error, run `shellcop-check-errors-of-other-windows-function'
+    (let* ((orig-w (get-buffer-window))
+           (wins (shellcop-all-windows))
+           err-wins)
+      (dolist (w wins)
+        (select-window w)
+        (when (and shellcop-sub-window-has-error-function
+                   (funcall shellcop-sub-window-has-error-function))
+          (push (buffer-name) err-wins)))
+      ;; back to original window
+      (select-window orig-w)
+
+      (comint-interrupt-subjob)
+      ;; wait 2 seconds
+      (sit-for 2)
+      (shellcop-erase-one-visible-buffer (buffer-name (current-buffer)))
+      (goto-char (point-max))
+
+      (cond
+       (err-wins
+        (message "Code syntax error in windows %s"
+                 (mapconcat 'identity err-wins " ")))
+       (shellcop-insert-shell-command-function
+        (funcall shellcop-insert-shell-command-function)))))
+
+   (t
+    (message "Can't erase buffer in %s" major-mode))))
+
+;;;###autoload
+(defun shellcop-erase-buffer (&optional n)
+  "Erase the content of the *Messages* buffer.
+N specifies the buffer to erase."
+  (interactive "P")
+  (cond
+   ((null n)
+    (shellcop-erase-one-visible-buffer "*Messages*"))
+
+   ((eq 1 n)
+    (shellcop-erase-one-visible-buffer "*shell*"))
+
+   ((eq 2 n)
+    (shellcop-erase-one-visible-buffer "*Javascript REPL*"))
+
+   ((eq 3 n)
+    (shellcop-erase-one-visible-buffer "*eshell*"))))
+
+(provide 'shellcop)
+;;; shellcop.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]