Skip to content

Commit

Permalink
Handle multiline strings correctly
Browse files Browse the repository at this point in the history
Fix #107. Fix #110.
  • Loading branch information
dungpa committed Jan 5, 2014
1 parent 11288b4 commit de5be4a
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 22 deletions.
54 changes: 53 additions & 1 deletion src/Fantomas.Tests/StringTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,56 @@ let d = 0o0777
let e = 1.40e10f
let f = 23.4M
let g = '\n'
"""
"""

[<Test>]
let ``should preserve triple-quote strings``() =
formatSourceString false "
type GetList() =
let switchvox_users_voicemail_getList_response = \"\"\"
</response>\"\"\"
let switchvox_users_voicemail_getList = \"\"\"
</request>\"\"\"
member self.X = switchvox_users_voicemail_getList_response
" config
|> prepend newline
|> should equal "
type GetList() =
let switchvox_users_voicemail_getList_response = \"\"\"
</response>\"\"\"
let switchvox_users_voicemail_getList = \"\"\"
</request>\"\"\"
member self.X = switchvox_users_voicemail_getList_response
"

[<Test>]
let ``should keep triple-quote strings``() =
formatSourceString false "
[<EntryPoint>]
let main argv =
use fun1 = R.eval(R.parse(text = \"\"\"
function(i) {
x <- rnorm(1000)
y <- rnorm(1000)
m <- lm(y~x)
m$coefficients[[2]]
}
\"\"\"))
0
" config
|> prepend newline
|> should equal "
[<EntryPoint>]
let main argv =
use fun1 = R.eval (R.parse (text = \"\"\"
function(i) {
x <- rnorm(1000)
y <- rnorm(1000)
m <- lm(y~x)
m$coefficients[[2]]
}
\"\"\"))
0
"
11 changes: 7 additions & 4 deletions src/Fantomas/CodeFormatter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ let parse isFsiFile s =
let fileName = if isFsiFile then "/tmp.fsi" else "/tmp.fs"
parseWith fileName s

let internal format isFsiFile s config =
let internal split (s : string) =
s.Replace("\r\n", "\n").Replace("\r", "\n").Split('\n')

let internal format isFsiFile (s : string) config =
// Use '\n' as the new line delimiter consistently
// It would be easier for F# parser
let s = s.Replace("\r\n", "\n").Replace("\r", "\n")
let s' =
Context.create config s
|> genParsedInput (parse isFsiFile s)
Expand Down Expand Up @@ -145,9 +151,6 @@ let internal getPatch startCol (lines : string []) =
if m.Success && col <= startCol + 4 then RecLet else loop (i - 1)
loop (lines.Length - 1)

let internal split (s : string) =
s.Replace("\r\n", "\n").Replace("\r", "\n").Split('\n')

let internal formatRangeFromString isFsiFile startLine startCol endLine endCol (lines : _ []) (s : string) config =
let s = s.Replace("\r\n", "\n").Replace("\r", "\n")
// Convert from range to string positions
Expand Down
35 changes: 24 additions & 11 deletions src/Fantomas/CodeFormatter.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,36 @@ open Fantomas.CodeFormatter

let config = { FormatConfig.Default with StrictMode = false }

let test s = formatSourceString false s config |> printfn "%A";;
let test (s : string) =
formatSourceString false (s.Replace("\r\n", "\n")) config |> printfn "%A";;

fsi.AddPrinter (fun (p : Microsoft.FSharp.Compiler.Range.pos) -> p.ToString())
fsi.AddPrinter (fun (r : Microsoft.FSharp.Compiler.Range.range) -> r.ToString())

let result =
formatAroundCursor false (makePos 4 10) """
let comp =
eventually { for x in 1 .. 2 do
printfn " x = %d" x
return 3 + 4 }
""" config;;
test "
[<EntryPoint>]
let main argv =
use fun1 = R.eval(R.parse(text = \"\"\"
function(i) {
x <- rnorm(1000)
y <- rnorm(1000)
m <- lm(y~x)
m$coefficients[[2]]
}
\"\"\"))
0
";;

test """
let hello() = "hello world"
test "
type GetList() =
let switchvox_users_voicemail_getList_response = \"\"\"
</response>\"\"\"
let switchvox_users_voicemail_getList = \"\"\"
</request>\"\"\"
(* This is a comment. *)""";;
member self.X = switchvox_users_voicemail_getList_response
";;

test """
(new CsvFile<_>(new Func<_, _, _>(fun (parent : obj) (row : string[]) -> CommonRuntime.GetNonOptionalValue("Name", CommonRuntime.ConvertString(TextConversions.AsOption(row.[0])), TextConversions.AsOption(row.[0])), CommonRuntime.GetNonOptionalValue("Distance", CommonRuntime.ConvertDecimal("", TextConversions.AsOption(row.[1])), TextConversions.AsOption(row.[1])), CommonRuntime.GetNonOptionalValue("Time", CommonRuntime.ConvertDecimal("", TextConversions.AsOption(row.[2])), TextConversions.AsOption(row.[2]))), new Func<_, _>(fun (row : _ * _ * _) -> [| CommonRuntime.ConvertStringBack(CommonRuntime.GetOptionalValue((let x, _, _ = row in x))); CommonRuntime.ConvertDecimalBack("", CommonRuntime.GetOptionalValue((let _, x, _ = row in x))); CommonRuntime.ConvertDecimalBack("", CommonRuntime.GetOptionalValue((let _, _, x = row in x))) |]), (ProviderFileSystem.readTextAtRunTimeWithDesignTimeOptions @"C:\Dev\FSharp.Data-master\src\..\tests\FSharp.Data.Tests\Data" "" "SmallTest.csv"), "", '"', true, false)).Cache()
Expand Down
4 changes: 2 additions & 2 deletions src/Fantomas/FormatConfig.fs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ type internal Context =
Content = ""; Positions = [||]; Comments = Dictionary(); Directives = Dictionary() }

static member create config (content : string) =
let content = content.Replace("\r\n", "\n")
let content = content.Replace("\r\n", "\n").Replace("\r", "\n")
let positions =
content.Split('\r', '\n')
content.Split('\n')
|> Seq.map (fun s -> String.length s + 1)
|> Seq.scan (+) 0
|> Seq.toArray
Expand Down
14 changes: 10 additions & 4 deletions src/Fantomas/SourceParser.fs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module internal Fantomas.SourceParser

open System
open System.Diagnostics
open Microsoft.FSharp.Compiler.Range
open Microsoft.FSharp.Compiler.Ast
open Microsoft.FSharp.Compiler.PrettyNaming
Expand All @@ -12,19 +13,24 @@ type Composite<'a, 'b> =
| Pair of 'b * 'b
| Single of 'a

#if INTERACTIVE
type Debug = Console
#endif

/// Get source string content based on range value
let lookup (r : range) (c : Context) =
if r.EndLine <= c.Positions.Length then
let start = c.Positions.[r.StartLine-1] + r.StartColumn
let finish = c.Positions.[r.EndLine-1] + r.EndColumn - 1
let content = c.Content
let s = content.[start..finish]
if s.Contains("\n") then
Debug.WriteLine("Content: {0} at start = {1}, finish = {2}", s, start, finish)
if s.Contains("\\\n") then
// Terrible hack to compensate the offset made by F# compiler
let last = content.[c.Positions.[r.EndLine-1]..finish]
let offset = last.Length - last.TrimStart(' ').Length
if finish + offset >= content.Length then content.[start..]
else content.[start..finish + offset]
let offset = min (last.Length - last.TrimStart(' ').Length) (content.Length - finish - 1)
Debug.WriteLine("Content after patch: {0} with offset = {1}", s, offset)
content.[start..finish + offset]
else s
else ""

Expand Down

0 comments on commit de5be4a

Please sign in to comment.