Skip to content

Commit

Permalink
Smarter verb-read-file + verb-body-lf-to-crlf in Emacs 28.1+
Browse files Browse the repository at this point in the history
  • Loading branch information
federicotdn committed Jul 8, 2024
1 parent c1a16c3 commit 8a2d425
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 8 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,11 @@ Content-Type: application/xml
{{(verb-part)}}
```

**Important**: In most cases, you will also need to apply the `verb-body-lf-to-crlf` function to your request before it is sent. This is needed to ensure that all line endings in the request body use CRLF instead of just LF. This is also shown in the example above.
> [!IMPORTANT]
> In most cases, you will also need to apply the `verb-body-lf-to-crlf` function to your request before it is sent. This is needed to ensure that all line endings in the request body use CRLF instead of just LF. This is also shown in the example above.
> [!NOTE]
> `verb-body-lf-to-crlf` will automatically ignore content specifically inserted with `verb-read-file`, so it will not break your requests in the file read contained newlines. This feature only works on Emacs 28.1 and newer.
### Base Headers

Expand Down
17 changes: 16 additions & 1 deletion test/verb-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -2892,6 +2892,11 @@
(should (equal (verb--get-accept-header '(("Foo" . "Bar") ("accept" . "xyz")))
"xyz")))

(ert-deftest test-read-file-lf-prop ()
(let ((b (verb-read-file "test/test.txt")))
(should (equal (get-text-property 1 'verb-lf-keep b) t))
(should (equal (get-text-property 14 'verb-lf-keep b) t))))

(ert-deftest test-generate-multipart-boundary ()
(let ((boundary (verb--generate-multipart-boundary))
(boundary2 (verb--generate-multipart-boundary)))
Expand Down Expand Up @@ -2931,7 +2936,17 @@
"two")))
(should (string= (oref aux body)
(join-lines "one\r"
"two"))))
"two")))

(setq aux (verb-body-lf-to-crlf (text-as-spec "get https://hello.com\n"
"\n"
(propertize "one\n" 'verb-lf-keep t)
"two\n"
"three")))
(should (string= (oref aux body)
(join-lines "one"
"two\r"
"three"))))

(ert-deftest test-multipart-boundary-error-no-boundary ()
(should-error
Expand Down
11 changes: 11 additions & 0 deletions verb-util.el
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,16 @@ If `verb-enable-log' is nil, do not log anything."
"Return non-nil if strings S1 and S2 are equal, ignoring case."
(string= (downcase s1) (downcase s2)))

(defun verb-util--object-intervals (object)
"Call function `object-intervals' on OBJECT if possible.
Otherwise, or if calling the function returns nil, return a single
interval covering the whole object, with no properties."
;; TODO: Update once Verb depends on Emacs 28.1+.
(let ((default (list (list 0 (length object) nil))))
(if (fboundp 'object-intervals)
(or (funcall #'object-intervals object)
default)
default)))

(provide 'verb-util)
;;; verb-util.el ends here
30 changes: 24 additions & 6 deletions verb.el
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ all the request specs in SPECS, in the order they were passed in."
;; specs already exists which means called from ob-verb block and loaded.
(unless specs
(verb-load-prelude-files-from-hierarchy))
(let ((point (point))
(let ((p (point))
done final-spec)
(save-restriction
(widen)
Expand All @@ -1002,7 +1002,7 @@ all the request specs in SPECS, in the order they were passed in."
;; If there's at least one heading above us, go up through the
;; headings tree taking a request specification from each level.
(while (not done)
(let ((spec (verb--request-spec-from-heading point)))
(let ((spec (verb--request-spec-from-heading p)))
(when spec (push spec specs)))
(setq done (not (verb--up-heading))))))
(if specs
Expand Down Expand Up @@ -1240,11 +1240,15 @@ buffer used to show the values."
"Return a buffer with the contents of FILE.
If CODING-SYSTEM system is a valid coding system, use it when reading
the file contents (see `coding-system-for-read' for more information).
Set the buffer's `verb-kill-this-buffer' variable locally to t."
Set the buffer's `verb-kill-this-buffer' variable locally to t.
Additionally, add the `verb-lf-keep' property to all of the resulting
buffer's text, to prevent function `verb-body-lf-to-crlf' from
potentially modifying it."
(with-current-buffer (generate-new-buffer " *verb-temp*")
(buffer-disable-undo)
(let ((coding-system-for-read coding-system))
(insert-file-contents file))
(add-text-properties (point-min) (point-max) '(verb-lf-keep t))
(setq verb-kill-this-buffer t)
(current-buffer)))

Expand Down Expand Up @@ -2440,9 +2444,23 @@ part, insert the final boundary delimiter."
(concat "--" boundary "--"))))

(defun verb-body-lf-to-crlf (rs)
"Prepend a carriage-return before all line-feeds in RS's body."
(oset rs body (replace-regexp-in-string "\n" "\r\n" (oref rs body)))
rs)
"Prepend a carriage-return before all line-feeds in RS's body.
Do this only for intervals of the string not having the `verb-lf-keep'
property."
(let* ((body (oref rs body))
(intervals (verb-util--object-intervals body))
parts)
(dolist (elem intervals)
(let* ((start (nth 0 elem))
(end (nth 1 elem))
(props (nth 2 elem))
(s (substring body start end)))
(push (if (plist-member props 'verb-lf-keep)
s
(replace-regexp-in-string "\n" "\r\n" s))
parts)))
(oset rs body (string-join (nreverse parts)))
rs))

(defun verb--eval-string (s &optional context)
"Eval S as Lisp code and return the result.
Expand Down

0 comments on commit 8a2d425

Please sign in to comment.