1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
namespace MonoDevelop.FSharp
open System
open MonoDevelop.Core
open MonoDevelop.Ide.Editor
open MonoDevelop.Ide.Editor.Extension
type FSharpTextPasteHandler(editor:TextEditor) =
inherit TextPasteHandler()
override x.GetCopyData(offset, _length) =
// get the indent level the line was originally at
let line = editor.OffsetToLineNumber offset
let indent = editor.GetLineIndent line
[|byte indent.Length|]
override x.PostFomatPastedText (_offset, _length) = ()
override x.FormatPlainText(offset, text, copyData) =
if editor.Options.IndentStyle = IndentStyle.Smart ||
editor.Options.IndentStyle = IndentStyle.Virtual then
// adjust the original indentation size
// for the new location
let location = editor.OffsetToLocation offset
if location.Column > 1 then
let getIndent (line:string) =
line.Length - (String.trimStart [|' '|] line).Length
let fixIndent (line:string, indentDifference:int) =
if indentDifference > 0 then
(String(' ', indentDifference)) + line
else
line.Substring -indentDifference
let line = location.Line
let insertionIndent = editor.GetLineIndent line
let lines = String.getLines text
let firstLine = lines.[0]
let firstLineIndent = if copyData.Length > 0 then
int copyData.[0]
else
getIndent firstLine
let indentDifference = insertionIndent.Length - firstLineIndent
let remainingLines = lines |> Seq.skip (1)
|> Seq.map(fun line -> fixIndent(line, indentDifference))
let lines = remainingLines
|> Seq.append (seq [(String.trimStart [|' '|] firstLine)])
let res = String.Join (editor.Options.DefaultEolMarker, lines)
res
else
text
else
text
type FSharpIndentationTracker(editor:TextEditor) =
inherit IndentationTracker ()
let indentSize = editor.Options.IndentationSize
do
editor.SetTextPasteHandler (FSharpTextPasteHandler(editor))
// Lines ending in these strings will be indented
let indenters = ["=";" do"; "("; "{";"[";"[|";"->";" try"; " then"; " else"; "("]
let (|AddIndent|_|) (x:string) =
if indenters |> List.exists(x.EndsWith) then Some ()
else None
let (|Match|_|) (x:string) =
if x.EndsWith "with" && x.Contains("match ") then Some (x.LastIndexOf "match ")
else None
let initialWhiteSpace (s:string) offset =
if offset >= s.Length then 0 else
let s = s.Substring offset
s.Length - s.TrimStart([|' '|]).Length
let rec getIndentation lineDistance (line: IDocumentLine) =
if line = null then "" else
match editor.GetLineText(line.LineNumber).TrimEnd() with
| x when String.IsNullOrWhiteSpace(x) -> getIndentation (lineDistance + 1) line.PreviousLine
| Match i when lineDistance < 2 -> String(' ', i)
| AddIndent when lineDistance < 2 -> String(' ', line.GetIndentation(editor).Length + indentSize)
| _ -> line.GetIndentation editor
let getIndentString lineNumber =
let caretColumn = editor.CaretColumn
let line = editor.GetLine lineNumber
let indentation = getIndentation 0 line
if line = null then indentation else
// Find white space in front of the caret and strip it out
let text = editor.GetLineText(line.LineNumber)
//TODO using 0 instead of column, which we dont have now
let reIndent = 0 = text.Length + 1 && caretColumn = 1
if not reIndent then indentation else
let indent = getIndentation 0 (line.PreviousLine)
let initialWs = initialWhiteSpace text 0
if initialWs >= indent.Length then indentation else
indent.Substring(initialWhiteSpace text 0)
override x.GetIndentationString (lineNumber) =
try
let line = editor.GetLine (lineNumber)
let indent =
if line = null then "" else
getIndentString lineNumber
LoggingService.LogDebug ("FSharpIndentationTracker: indent: '{0}'", indent)
indent
with
| ex -> LoggingService.LogError ("FSharpIndentationTracker", ex)
""
override x.SupportedFeatures = IndentatitonTrackerFeatures.None
|