Skip to content

Commit

Permalink
Implement substring formatting with fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
jackfirth committed Aug 21, 2024
1 parent 50b958f commit e0b5b97
Showing 1 changed file with 43 additions and 27 deletions.
70 changes: 43 additions & 27 deletions private/refactoring-result.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@

(require fancy-app
fmt
guard
(only-in racket/list last)
racket/match
racket/string
rebellion/base/immutable-string
rebellion/base/range
rebellion/base/symbol
Expand All @@ -42,6 +45,11 @@
resyntax/private/syntax-replacement)


(module+ test
(require (submod "..")
rackunit))


;@----------------------------------------------------------------------------------------------------


Expand Down Expand Up @@ -104,39 +112,21 @@
;; This function is the sole integration point between Resyntax and fmt. It is used by Resyntax to
;; format any refactored code initially generated by Resyntax.
(define (format-refactored-code refactored-source-code #:start start #:end end)
;; TODO: actually use start and end to format only that range once fmt supports it.
(define formatted-source-code
;; Appending a newline is needed because fmt strips the trailing newline from files for some
;; reason.
(string-append (program-format refactored-source-code) "\n"))
(define changed-code-substring (substring refactored-source-code start end))
(define initial-columns (string-column-offset refactored-source-code start))
(define formatted-code-substring
(program-format changed-code-substring #:indent initial-columns))

;; Formatting can change the total length of the program source code, and we want to tell the
;; caller where the new endpoint of the formatted source range is.
(define formatting-delta
(- (string-length formatted-source-code) (string-length refactored-source-code)))
(- (string-length formatted-code-substring) (string-length changed-code-substring)))
(define end-after-formatting (+ end formatting-delta))

;; Before handing the reformatted code back to the caller, we double check that fmt didn't touch
;; anything outside the requested range. If it did, raise an exception with an error message that
;; explains the problem and includes the code both before and after formatting.
(unless (and (equal? (substring refactored-source-code 0 start)
(substring formatted-source-code 0 start))
(equal? (substring refactored-source-code end)
(substring formatted-source-code end-after-formatting)))
(raise
(exn:fail:refactoring-formatting-out-of-bounds
(string-append "format-refactored-code: failed to format refactored code;\n"
" fmt edited other code outside the target source code range\n"
(format " code before formatting:\n~a\n"
(string-indent refactored-source-code #:amount 3))
(format " code after formatting:\n~a\n"
(string-indent formatted-source-code #:amount 3))
(format " target source range: [~a, ~a)" start end))
(current-continuation-marks)
refactored-source-code
formatted-source-code
start
end)))
(define formatted-source-code
(string-append (substring refactored-source-code 0 start)
formatted-code-substring
(substring refactored-source-code end)))

(formatted-code-subrange formatted-source-code start end-after-formatting))

Expand Down Expand Up @@ -217,3 +207,29 @@
(sub1 (linemap-position-to-start-of-line map start))
(sub1 (linemap-position-to-end-of-line map formatted-end)))))
(in-lines (open-input-string replacement-text)))


(define/guard (string-column-offset str position)
(define up-to-position (substring str 0 position))
(guard (non-empty-string? up-to-position) #:else 0)
(string-length (last (string-split up-to-position "\n" #:trim? #false))))


(module+ test
(test-case "string-column-offset"
(check-equal? (string-column-offset "" 0) 0)
(check-equal? (string-column-offset "apple" 0) 0)
(check-equal? (string-column-offset "apple" 4) 4)
(check-equal? (string-column-offset "apple\nbanana" 0) 0)
(check-equal? (string-column-offset "apple\nbanana" 4) 4)
(check-equal? (string-column-offset "apple\nbanana" 6) 0)
(check-equal? (string-column-offset "apple\nbanana" 8) 2)
(check-equal? (string-column-offset "apple\nbanana" 12) 6)
(check-equal? (string-column-offset "apple\nbanana\ngrape" 0) 0)
(check-equal? (string-column-offset "apple\nbanana\ngrape" 4) 4)
(check-equal? (string-column-offset "apple\nbanana\ngrape" 6) 0)
(check-equal? (string-column-offset "apple\nbanana\ngrape" 8) 2)
(check-equal? (string-column-offset "apple\nbanana\ngrape" 12) 6)
(check-equal? (string-column-offset "apple\nbanana\ngrape" 13) 0)
(check-equal? (string-column-offset "apple\nbanana\ngrape" 16) 3)
(check-equal? (string-column-offset "apple\nbanana\ngrape" 18) 5)))

0 comments on commit e0b5b97

Please sign in to comment.