help-gnu-emacs
[Top][All Lists]
Advanced

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

Re: send selection or current line to Terminal/iTerm


From: John Mastro
Subject: Re: send selection or current line to Terminal/iTerm
Date: Sat, 14 Jun 2014 09:52:05 -0700

Hi klebsiella,

klebsiella <address@hidden> wrote:
> It works like a charm ... very efficient,
>
> Though, one small improvement will be to send the whole current line,
> instead of the symbol only, when no region is selected.

[snip]

> Also, but very minor, would be to strip/skip empty lines and
> eventually move cursor to the next line of code (but this is really
> not very important) All best and thanks again for the very good job

You're welcome - I'm glad it worked.

Here's a version with the changes you suggested. The "thing" to send
when there's no active region (i.e. selection) is configurable,
with the current line as the default.

Let me know if it's what you have in mind.

By the way - is this useful for others? If so I could release it on e.g.
MELPA.

Best,

John

;;; iterm.el - send text to a running iTerm instance

(require 'pcase)
(require 'thingatpt)

;; To match SublimeText's key binding:
;; (global-set-key (kbd "<C-return>") 'iterm-send-text)

(defvar iterm-default-thing 'line
  "The \"thing\" to send if no region is active.
Can be any symbol understood by `bounds-of-thing-at-point'.")

(defvar iterm-empty-line-regexp "^[[:space:]]*$"
  "Regexp to match empty lines, which will not be sent to iTerm.
Set to nil to disable removing empty lines.")

(defun iterm-escape-string (str)
  (let* ((str (replace-regexp-in-string "\\\\" "\\\\" str nil t))
         (str (replace-regexp-in-string "\"" "\\\"" str nil t)))
    str))

(defun iterm-last-char-p (str char)
  (let ((length (length str)))
    (and (> length 0)
         (char-equal (elt str (- length 1)) char))))

(defun iterm-chop-newline (str)
  (let ((length (length str)))
    (if (iterm-last-char-p str ?\n)
        (substring str 0 (- length 1))
      str)))

(defun iterm-maybe-add-newline (str)
  (if (iterm-last-char-p str ? )
      (concat str "\n")
    str))

(defun iterm-handle-newline (str)
  (iterm-maybe-add-newline (iterm-chop-newline str)))

(defun iterm-maybe-remove-empty-lines (str)
  (if iterm-empty-line-regexp
      (let ((regexp iterm-empty-line-regexp)
            (lines (split-string str "\n")))
        (mapconcat 'identity
                   (delq nil (mapcar (lambda (line)
                                       (unless (string-match-p regexp line)
                                         line))
                                     lines))
                   "\n"))
    str))

(defun iterm-send-string (str)
  "Send STR to a running iTerm instance."
  (let* ((str (iterm-maybe-remove-empty-lines str))
         (str (iterm-handle-newline str))
         (str (iterm-escape-string str)))
    (shell-command
     (concat "osascript -e 'tell app \"iTerm\"' "
             "-e 'set mysession to current session of current terminal' "
             (format "-e 'tell mysession to write text \"%s\"' " str)
             "-e 'end tell'"))))

(defun iterm-text-bounds ()
  (pcase-let ((`(,beg . ,end) (if (use-region-p)
                                  (cons (region-beginning) (region-end))
                                (bounds-of-thing-at-point
                                 iterm-default-thing))))
    (list beg end)))

(defun iterm-send-text (beg end)
  "Send buffer text in region from BEG to END to iTerm.
If called interactively without an active region, send the symbol
at point instead."
  (interactive (iterm-text-bounds))
  (let ((str (iterm-escape-string (buffer-substring-no-properties beg
end))))
    (iterm-send-string str))
  (forward-line 1))

(provide 'iterm)


reply via email to

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