Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,4 @@ The following variables are available for customization (see more via `M-x custo
- Cmd `lua-send-defun`: send current top-level function
- Cmd `lua-send-region`: send active region
- Cmd `lua-restart-with-whole-file`: restart REPL and send whole buffer
- Var `lua-send-string-max-size` (default `512` for Mac OS, `nil` for other platforms): maximum size of string that can be sent to subprocess in one operation, because some platforms are implicitly limiting the buffer size and the data arrives incomplete
52 changes: 50 additions & 2 deletions lua-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ Should be a list of strings."
:type 'boolean
:group 'lua)

(defcustom lua-send-string-max-size (if (string-equal system-type "darwin") 512 nil)
"Maximum size of string that can be sent to inferior shell."
:type '(choice nil string)
:group 'lua)

(defcustom lua-documentation-function 'browse-url
"Function used to fetch the Lua reference manual."
:type `(radio (function-item browse-url)
Expand Down Expand Up @@ -1686,8 +1691,13 @@ This function just searches for a `end' at the beginning of a line."
"end")
" "))

(defun lua--send-process-init-code ()
"Send initialization code to REPL."
;; XXX: send in chunks if initialization code exceeds send-string-max-size
(lua-send-string lua-process-init-code))

(defun lua-make-lua-string (str)
"Convert string to Lua literal."
"Convert string STR to Lua literal."
(save-match-data
(with-temp-buffer
(insert str)
Expand Down Expand Up @@ -1769,6 +1779,8 @@ When called interactively, switch to the process buffer."
"Send STR plus a newline to the Lua process.

If `lua-process' is nil or dead, start a new process first."
(when (and lua-send-string-max-size (> (length str) lua-send-string-max-size))
(error (format "Cannot send string of length %s (max length=%s)" (length str) lua-send-string-max-size)))
(unless (string-equal (substring str -1) "\n")
(setq str (concat str "\n")))
(process-send-string (lua-get-create-process) str))
Expand Down Expand Up @@ -1830,9 +1842,45 @@ Otherwise, return START."
(lua-make-lua-string region-str)
(lua-make-lua-string lua-file)
lineno)))
(lua-send-string command)
(if (or (null lua-send-string-max-size) (<= (length command) lua-send-string-max-size))
(lua-send-string command)
(lua-send-region-chunked region-str lua-file lineno lua-send-string-max-size))
(when lua-always-show (lua-show-process-buffer))))

(defun lua--split-string-into-lua-literals (str literal-max-length &optional func)
(let* (lua-literals
(func (or func (lambda (s) (setq lua-literals (cons s lua-literals)))))
chunk-begin chunk-end chunk chunk-as-lua-string)
(with-temp-buffer
(insert str)
(goto-char (point-min))
(while (< (point) (point-max))
(setq chunk-begin (point)
chunk-end (+ (point) literal-max-length))
;; For every special character that has to be quoted with a backslash,
;; decrease payload to account for the extra character.
(while (and (< (point) (min (point-max) chunk-end))
(re-search-forward "[\"'\\\t\\\n]" chunk-end 'noerror))
(setq chunk-end (1- chunk-end)))
(goto-char chunk-end)
(setq chunk (buffer-substring-no-properties chunk-begin (point)))
(funcall func (lua-make-lua-string chunk))))
(nreverse lua-literals)))

(defun lua-send-region-chunked (region-str lua-file lineno max-size)
"Send REGION-STR from LUA-FILE at LINENO in chunks of no more than MAX-SIZE."
;; XXX: make enable/disable-prompt-commands customizable
(let* ((disable-prompt-command "_PROMPT = ''; _PROMPT2 = ''")
(enable-prompt-command "_PROMPT = nil; _PROMPT2 = nil")
(between-quotes-max-size (- max-size 4)))
(lua-send-string disable-prompt-command)
(lua-send-string "print(''); luamode_loadstring(\"\"")
(lua--split-string-into-lua-literals
region-str between-quotes-max-size
(lambda (s) (lua-send-string (format "..%s" s))))
(lua-send-string (format ",%s,%d)" (lua-make-lua-string lua-file) lineno))
(lua-send-string enable-prompt-command)))

(defun lua-prompt-line ()
(save-excursion
(save-match-data
Expand Down
37 changes: 37 additions & 0 deletions test/test-inferior-process.el
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@
(expect comint-prompt-regexp :to-equal "^"))
(expect comint-prompt-regexp :to-equal "^")))

(describe "Splitting Lua code into literals of specified size"
(it "splits strings into same-size Lua literals"
(expect (lua--split-string-into-lua-literals "foobarbaz" 3)
:to-equal '("'foo'" "'bar'" "'baz'")))

(it "leaves last lua literal shorter if necessary"
(expect (lua--split-string-into-lua-literals "foobarba" 3)
:to-equal '("'foo'" "'bar'" "'ba'"))
(expect (lua--split-string-into-lua-literals "foobarb" 3)
:to-equal '("'foo'" "'bar'" "'b'"))
(expect (lua--split-string-into-lua-literals "foobar" 3)
:to-equal '("'foo'" "'bar'")))

(it "escapes special characters and does not exceed max-length"
(expect (lua--split-string-into-lua-literals "foo\nbar" 3)
:to-equal '("'foo'" "'\\nb'" "'ar'")))

(it "cuts literal short if it cannot fit a special character"
(expect (lua--split-string-into-lua-literals "fo\nbar" 3)
:to-equal '("'fo'" "'\\nb'" "'ar'"))))

(describe "Sending region chunked"
(it "does that"
(with-lua-buffer
(insert "x = '|01234567890|1234567890|1234567890|'")
(lua-start-process)
(let ((lua-string-max-size 20))
(lua-send-buffer))
(lua-send-string "print(x)")
(while (accept-process-output (lua-get-create-process) 0 200))
(with-current-buffer lua-process-buffer
(let* ((buf (buffer-substring-no-properties (point-min) (point-max)))
(buf-lines (cdr (split-string buf "\n" nil))))
(expect (nth 1 (nreverse buf-lines))
:to-equal "> |01234567890|1234567890|1234567890|"))))))



(require 'compile)
(if (fboundp 'compilation--loc->file-struct)
Expand Down