Welcome to mirror list, hosted at ThFree Co, Russian Federation.

FSharpIndentationTracker.fs « MonoDevelop.FSharpBinding « fsharpbinding « external « main - github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1b8bf0d563652868106a14ca79b490d24a9a0ac7 (plain)
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