├── .gitattributes ├── .gitignore ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── .paket ├── paket.bootstrapper.exe └── paket.targets ├── LICENSE.md ├── Makefile ├── MonoDevelop.FSharp.Gui ├── FSharpCompilerOptionsWidget.cs ├── FSharpSettingsWidget.cs ├── MonoDevelop.FSharp.Gui.csproj └── gtk-gui │ ├── MonoDevelop.FSharp.Gui.FSharpCompilerOptionsWidget.cs │ ├── MonoDevelop.FSharp.Gui.FSharpSettingsWidget.cs │ ├── generated.cs │ └── gui.stetic ├── MonoDevelop.FSharp.Shared ├── AssemblyInfo.fs ├── Completions.fs ├── Extensions.fs ├── FSharpSymbolHelper.fs ├── KeywordList.fs ├── Lexer.fs ├── MonoDevelop.FSharp.Shared.fsproj ├── ParameterHinting.fs ├── Parser.fs └── paket.references ├── MonoDevelop.FSharp.Tests ├── Checker.fs ├── CompletionListsAdhocManualTests.fsx ├── CompletionTests.fs ├── DebuggerExpressionResolver.fs ├── FSharpUnitTestTextEditorExtensionTests.fs ├── GlobalSearch.fs ├── HighlightUsagesTests.fs ├── IndentationTrackerTests.fs ├── MonoDevelop.FSharp.Tests.fsproj ├── ParameterHinting.fs ├── ParsingTests.fs ├── ProjectCracking.fs ├── ProjectTests.fs ├── Samples │ └── Xamarin.iOS.fsproj ├── Script.fsx ├── SemanticHighlighting.fs ├── SyntaxHighlighting.fs ├── TestBase.fs ├── TestDocument.fs ├── TestHelpers.fs ├── TestTooltipProvider.fs ├── TestViewContent.fs ├── TestWorkbenchWindow.fs └── paket.references ├── MonoDevelop.FSharp.sln ├── MonoDevelop.FSharpBinding ├── CompilerService.exe.config ├── FSharpBinding.addin.xml ├── FSharpBraceMatcher.fs ├── FSharpDebuggerExpressionResolver.fs ├── FSharpFoldingParser.fs ├── FSharpFormatter.fs ├── FSharpFormattingPanelWidget.fs ├── FSharpFormattingPolicy.fs ├── FSharpFormattingPolicy.xml ├── FSharpFormattingPolicyPanel.fs ├── FSharpHighlightUsagesExtension.fs ├── FSharpIndentationTracker.fs ├── FSharpInteractivePad.fs ├── FSharpNavigationTextEditorExtension.fs ├── FSharpOptionsPanels.fs ├── FSharpOutlineTextEditorExtension.fs ├── FSharpParsedDocument.fs ├── FSharpParser.fs ├── FSharpPathExtension.fs ├── FSharpProject.fs ├── FSharpProjectFileNodeExtension.fs ├── FSharpResolverProvider.fs ├── FSharpStylePolicy.xml ├── FSharpSymbolHelper.fs ├── FSharpSyntaxMode.fs ├── FSharpSyntaxMode.xml ├── FSharpTextEditorCompletion.fs ├── FSharpTokens.fs ├── FSharpTooltipProvider.fs ├── FSharpUnitTestTextEditorExtension.fs ├── FakeSearchCategory.fs ├── MonoDevelop.FSharp.fsproj ├── ProjectSearchCategory.fs ├── Properties │ └── AddinInfo.fs ├── RefactoringOperationsHandler.fs ├── Services │ ├── CompilerArguments.fs │ ├── CompilerLocationUtils.fs │ ├── CompilerService.fs │ ├── Extensions.fs │ ├── FSharpConsoleView.fs │ ├── FileService.fs │ ├── InteractiveSession.fs │ ├── LanguageService.fs │ ├── Lexer.fs │ ├── MDLanguageService.fs │ ├── NRefactory.fs │ ├── OrderAssemblyReferences.fs │ ├── Parameters.fs │ ├── Parser.fs │ └── TooltipHelpers.fs ├── Templates │ ├── AssemblyInfo.xft.xml │ ├── EmptyFSharpScript.xft.xml │ ├── EmptyFSharpSignature.xft.xml │ ├── EmptyFSharpSource.xft.xml │ ├── FSharp-templates.xml │ ├── FSharpConsoleProject.xpt.xml │ ├── FSharpGtkProject.xpt.xml │ ├── FSharpLibraryProject.xpt.xml │ ├── FSharpNUnitLibraryProject.xpt.xml │ ├── FSharpNUnitTestType.xft.xml │ ├── FSharpTutorialProject.xpt.xml │ ├── PortableLibrary.xpt.xml │ └── SharedAssetsProject.xpt.xml ├── UnformattedTextFileDescriptionTemplate.fs ├── paket.references ├── templates.AssemblyInfo.xft.xml └── templates.targets ├── MonoDevelop.FSharpi.Service ├── AssemblyInfo.fs ├── MonoDevelop.FSharpInteractive.Service.fsproj ├── Program.fs ├── app.config ├── lib │ └── FSharp.Compiler.Interactive.Settings.dll └── paket.references ├── README.md ├── RELEASE_NOTES.md ├── addin-project.xml ├── build.cmd ├── build.fsx ├── build.sh ├── configure.sh ├── launch.bat ├── paket.dependencies └── paket.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | 24 | *.sh text eol=lf 25 | *.fs text eol=lf 26 | Makefile.orig text eol=lf 27 | configure.sh text eol=lf 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # F# 2 | [Bb]in/ 3 | [Oo]bj/ 4 | .fake/ 5 | monodevelop/pack/* 6 | monodevelop/packages/* 7 | monodevelop/build-and* 8 | repository/* 9 | *.suo 10 | *.pidb 11 | *.userprefs 12 | *.GhostDoc.xml 13 | *.user 14 | *.dll 15 | *.pdb 16 | *.cache 17 | *.swp 18 | *.swo 19 | *.swn 20 | *.pyc 21 | *.orig 22 | ======= 23 | *~ 24 | pack/* 25 | 26 | .DS_Store 27 | 28 | /packages 29 | 30 | /MonoDevelop.FSharp.Tests/tests 31 | 32 | .paket/paket.exe 33 | -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/zarchive-xamarin-monodevelop-fsharp-addin/43dc90dbb354f06458dc7f48614716533f8735c6/.nuget/NuGet.exe -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) 32 | 33 | 34 | 35 | 36 | $(SolutionDir).nuget 37 | packages.config 38 | 39 | 40 | 41 | 42 | $(NuGetToolsPath)\NuGet.exe 43 | @(PackageSource) 44 | 45 | "$(NuGetExePath)" 46 | mono --runtime=v4.0.30319 $(NuGetExePath) 47 | 48 | $(TargetDir.Trim('\\')) 49 | 50 | -RequireConsent 51 | -NonInteractive 52 | 53 | "$(SolutionDir) " 54 | "$(SolutionDir)" 55 | 56 | 57 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 58 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 59 | 60 | 61 | 62 | RestorePackages; 63 | $(BuildDependsOn); 64 | 65 | 66 | 67 | 68 | $(BuildDependsOn); 69 | BuildPackage; 70 | 71 | 72 | 73 | 74 | 75 | 76 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | 98 | 100 | 101 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /.paket/paket.bootstrapper.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/zarchive-xamarin-monodevelop-fsharp-addin/43dc90dbb354f06458dc7f48614716533f8735c6/.paket/paket.bootstrapper.exe -------------------------------------------------------------------------------- /.paket/paket.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | 7 | true 8 | $(MSBuildThisFileDirectory) 9 | $(MSBuildThisFileDirectory)..\ 10 | /Library/Frameworks/Mono.framework/Commands/mono 11 | mono 12 | 13 | 14 | 15 | $(PaketToolsPath)paket.exe 16 | $(PaketToolsPath)paket.bootstrapper.exe 17 | "$(PaketExePath)" 18 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" 19 | "$(PaketBootStrapperExePath)" 20 | $(MonoPath) --runtime=v4.0.30319 $(PaketBootStrapperExePath) 21 | 22 | $(MSBuildProjectDirectory)\paket.references 23 | $(MSBuildProjectFullPath).paket.references 24 | $(PaketCommand) restore --references-files "$(PaketReferences)" 25 | $(PaketBootStrapperCommand) 26 | 27 | RestorePackages; $(BuildDependsOn); 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for compiling, installing and packing F# MonoDevelop plugin on Mono 2 | # 3 | # run 'make' to compile the plugin against the installed version of MonoDevelop detected by ./configure.sh 4 | # run 'make install' to compile and install the plugin against the installed version of MonoDevelop detected by ./configure.sh 5 | # run 'make pack-all' to create a deployment binary packages for the known set of supported MonoDevelop versions 6 | 7 | VERSION=6.0.0 8 | 9 | MDTOOL = mono '../../build/bin/mdtool.exe' 10 | 11 | # (MDVERSION4) can be set to something like (3.0.4, 3.0.4.7) to compile 12 | # against the dependencies/... binaries for a specific version of MonoDevelop. This allows 13 | # us to prepare new editions of the binding for several different versions of MonoDevelop. 14 | MDVERSION4=6.0 15 | 16 | MDROOT=../../build 17 | 18 | 19 | # The default configuration is Release since Roslyn 20 | ifeq ($(config),) 21 | config=Release 22 | endif 23 | 24 | .PHONY: all 25 | 26 | all: build 27 | 28 | build: MonoDevelop.FSharpBinding/MonoDevelop.FSharp.fsproj MonoDevelop.FSharpBinding/FSharpBinding.addin.xml 29 | (xbuild MonoDevelop.FSharp.sln /p:Configuration=$(config)) 30 | 31 | pack: build 32 | -rm -fr pack/$(config) 33 | @-mkdir -p pack/$(config) 34 | $(MDTOOL) setup pack bin/FSharpBinding.dll -d:pack/$(config) 35 | 36 | install: pack 37 | $(MDTOOL) setup install -y pack/$(config)/MonoDevelop.FSharpBinding_$(MDVERSION4).mpack 38 | 39 | uninstall: 40 | $(MDTOOL) setup uninstall MonoDevelop.FSharpBinding 41 | 42 | release: 43 | $(MAKE) config=Release pack 44 | 45 | clean: 46 | -rm -fr bin 47 | -rm -fr pack 48 | -rm -fr MonoDevelop.FSharpBinding/MonoDevelop.FSharp.*.fsproj 49 | -rm -fr MonoDevelop.FSharpBinding/obj 50 | (cd MonoDevelop.FSharp.Gui && xbuild MonoDevelop.FSharp.Gui.csproj /target:Clean) 51 | 52 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Gui/FSharpCompilerOptionsWidget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace MonoDevelop.FSharp.Gui 3 | { 4 | [System.ComponentModel.ToolboxItem(true)] 5 | public partial class FSharpCompilerOptionsWidget : Gtk.Bin 6 | { 7 | public FSharpCompilerOptionsWidget () 8 | { 9 | this.Build (); 10 | } 11 | 12 | public Gtk.Entry EntryCommandLine { get { return this.entryCustomParameters; } } 13 | public Gtk.Entry EntryDefines { get { return this.entryDefines; } } 14 | public Gtk.CheckButton CheckOptimize { get { return this.checkOptimize; } } 15 | public Gtk.CheckButton CheckTailCalls { get { return this.checkTailCalls; } } 16 | public Gtk.CheckButton CheckXmlDocumentation { get { return this.checkXmlDocumentation; } } 17 | public Gtk.ComboBox ComboDebugInformation { get { return this.comboboxDebugInformation; } } 18 | public Gtk.CheckButton CheckDebugInformation { get { return this.checkGenerateDebugInformation; } } 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Gui/FSharpSettingsWidget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace MonoDevelop.FSharp.Gui 3 | { 4 | [System.ComponentModel.ToolboxItem(true)] 5 | public partial class FSharpSettingsWidget : Gtk.Bin 6 | { 7 | public FSharpSettingsWidget () 8 | { 9 | this.Build (); 10 | } 11 | 12 | public Gtk.CheckButton CheckInteractiveUseDefault { get { return checkInteractiveUseDefault; } } 13 | public Gtk.Button ButtonBrowse { get { return buttonBrowse; } } 14 | public Gtk.Entry EntryArguments { get { return entryArguments; } } 15 | public Gtk.CheckButton AdvanceLine { get { return advanceToNextLineCheckbox; } } 16 | public Gtk.Entry EntryPath { get { return entryPath; } } 17 | public Gtk.FontButton FontInteractive { get { return fontbutton1; } } 18 | public Gtk.CheckButton MatchThemeCheckBox { get { return matchThemeCheckbox; } } 19 | public Gtk.HBox ColorsHBox { get { return hbox7; } } 20 | public Gtk.ColorButton BaseColorButton { get { return baseColorButton; } } 21 | public Gtk.ColorButton TextColorButton { get { return textColorButton; } } 22 | public Gtk.CheckButton CheckCompilerUseDefault { get { return checkCompilerUseDefault; } } 23 | public Gtk.Button ButtonCompilerBrowse { get { return buttonCompilerBrowse; } } 24 | public Gtk.Entry EntryCompilerPath { get { return entryCompilerPath; } } 25 | public Gtk.CheckButton CheckHighlightMutables { get { return checkHighlightMutables; } } 26 | 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Gui/MonoDevelop.FSharp.Gui.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {FD0D1033-9145-48E5-8ED8-E2365252878C} 9 | Library 10 | FSharpBinding.Gui 11 | MonoDevelop.FSharp.Gui 12 | v4.5 13 | 14 | 15 | 16 | True 17 | full 18 | False 19 | ..\bin\ 20 | prompt 21 | 4 22 | True 23 | 24 | 25 | none 26 | True 27 | ..\bin\ 28 | prompt 29 | 4 30 | True 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | gui.stetic 47 | Designer 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Gui/gtk-gui/generated.cs: -------------------------------------------------------------------------------- 1 | 2 | // This file has been generated by the GUI designer. Do not modify. 3 | namespace Stetic 4 | { 5 | internal class Gui 6 | { 7 | private static bool initialized; 8 | 9 | internal static void Initialize (Gtk.Widget iconRenderer) 10 | { 11 | if ((Stetic.Gui.initialized == false)) { 12 | Stetic.Gui.initialized = true; 13 | } 14 | } 15 | } 16 | 17 | internal class BinContainer 18 | { 19 | private Gtk.Widget child; 20 | 21 | private Gtk.UIManager uimanager; 22 | 23 | public static BinContainer Attach (Gtk.Bin bin) 24 | { 25 | BinContainer bc = new BinContainer (); 26 | bin.SizeRequested += new Gtk.SizeRequestedHandler (bc.OnSizeRequested); 27 | bin.SizeAllocated += new Gtk.SizeAllocatedHandler (bc.OnSizeAllocated); 28 | bin.Added += new Gtk.AddedHandler (bc.OnAdded); 29 | return bc; 30 | } 31 | 32 | private void OnSizeRequested (object sender, Gtk.SizeRequestedArgs args) 33 | { 34 | if ((this.child != null)) { 35 | args.Requisition = this.child.SizeRequest (); 36 | } 37 | } 38 | 39 | private void OnSizeAllocated (object sender, Gtk.SizeAllocatedArgs args) 40 | { 41 | if ((this.child != null)) { 42 | this.child.Allocation = args.Allocation; 43 | } 44 | } 45 | 46 | private void OnAdded (object sender, Gtk.AddedArgs args) 47 | { 48 | this.child = args.Widget; 49 | } 50 | 51 | public void SetUiManager (Gtk.UIManager uim) 52 | { 53 | this.uimanager = uim; 54 | this.child.Realized += new System.EventHandler (this.OnRealized); 55 | } 56 | 57 | private void OnRealized (object sender, System.EventArgs args) 58 | { 59 | if ((this.uimanager != null)) { 60 | Gtk.Widget w; 61 | w = this.child.Toplevel; 62 | if (((w != null) 63 | && typeof(Gtk.Window).IsInstanceOfType (w))) { 64 | ((Gtk.Window)(w)).AddAccelGroup (this.uimanager.AccelGroup); 65 | this.uimanager = null; 66 | } 67 | } 68 | } 69 | } 70 | 71 | internal class ActionGroups 72 | { 73 | public static Gtk.ActionGroup GetActionGroup (System.Type type) 74 | { 75 | return Stetic.ActionGroups.GetActionGroup (type.FullName); 76 | } 77 | 78 | public static Gtk.ActionGroup GetActionGroup (string name) 79 | { 80 | return null; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Shared/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp.Shared 2 | open System.Reflection 3 | open System.Runtime.CompilerServices 4 | 5 | [] 6 | [] 7 | [] 8 | [] 9 | [] 10 | [] 11 | [] 12 | 13 | // The assembly version has the format {Major}.{Minor}.{Build}.{Revision} 14 | 15 | [] 16 | 17 | //[] 18 | //[] 19 | 20 | () 21 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Shared/MonoDevelop.FSharp.Shared.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Debug 4 | AnyCPU 5 | 8.0.30703 6 | 2.0 7 | {AF5FEAD5-B50E-4F07-A274-32F23D5C504D} 8 | Library 9 | MonoDevelop.FSharp.Shared 10 | MonoDevelop.FSharp.Shared 11 | v4.5 12 | 4.4.0.0 13 | 14 | 15 | true 16 | full 17 | false 18 | bin\Debug 19 | DEBUG 20 | prompt 21 | false 22 | 23 | 24 | 25 | true 26 | bin\Release 27 | 28 | prompt 29 | false 30 | true 31 | 32 | 33 | 34 | 35 | 36 | True 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 57 | 58 | 59 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | ..\packages\ExtCore\lib\net40\ExtCore.dll 68 | True 69 | True 70 | 71 | 72 | 73 | 74 | 75 | 76 | ..\packages\ExtCore\lib\net45\ExtCore.dll 77 | True 78 | True 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | ..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll 88 | True 89 | True 90 | 91 | 92 | 93 | 94 | 95 | 96 | ..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll 97 | True 98 | True 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Shared/ParameterHinting.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp.Shared 2 | open Microsoft.FSharp.Compiler.SourceCodeServices 3 | 4 | module ParameterHinting = 5 | let getTooltipInformation (symbol: FSharpSymbolUse) = 6 | match symbol with 7 | | MemberFunctionOrValue m -> 8 | let parameters = 9 | match m.CurriedParameterGroups |> Seq.toList with 10 | | [single] -> 11 | single 12 | |> Seq.map (fun param -> 13 | match param.Name with 14 | | Some n -> n 15 | | _ -> param.DisplayName) 16 | |> List.ofSeq 17 | | _ -> [] 18 | let signature = SymbolTooltips.getFuncSignatureWithFormat symbol.DisplayContext m {Indent=3;Highlight=None} 19 | let summary = SymbolTooltips.getSummaryFromSymbol m 20 | ParameterTooltip.ToolTip (signature, summary, parameters) 21 | | _ -> ParameterTooltip.EmptyTip 22 | 23 | let parameterCount (symbol: FSharpSymbol) = 24 | match symbol with 25 | | :? FSharpMemberOrFunctionOrValue as fsm -> 26 | let cpg = fsm.CurriedParameterGroups 27 | cpg.[0].Count 28 | | _ -> 0 29 | 30 | let isParameterListAllowed (symbol: FSharpSymbol) = 31 | match symbol with 32 | | :? FSharpMemberOrFunctionOrValue as fsm 33 | when fsm.CurriedParameterGroups.Count > 0 -> 34 | //TODO: How do we handle non tupled arguments? 35 | let group = fsm.CurriedParameterGroups.[0] 36 | if group.Count > 0 then 37 | let last = group |> Seq.last 38 | last.IsParamArrayArg 39 | else 40 | false 41 | | _ -> false 42 | 43 | let getParameterName (symbol: FSharpSymbol) i = 44 | match symbol with 45 | | :? FSharpMemberOrFunctionOrValue as fsm 46 | when fsm.CurriedParameterGroups.Count > 0 && 47 | fsm.CurriedParameterGroups.[0].Count > 0 -> 48 | //TODO: How do we handle non tupled arguments? 49 | let group = fsm.CurriedParameterGroups.[0] 50 | let param = group.[i] 51 | match param.Name with 52 | | Some n -> n 53 | | None -> param.DisplayName 54 | | _ -> "" 55 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Shared/Parser.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp.Shared 2 | open System 3 | open Microsoft.FSharp.Compiler.SourceCodeServices 4 | open Microsoft.FSharp.Compiler 5 | open System.Globalization 6 | 7 | // -------------------------------------------------------------------------------------- 8 | /// Parsing utilities for IntelliSense (e.g. parse identifier on the left-hand side 9 | /// of the current cursor location etc.) 10 | module Parsing = 11 | let inline private tryGetLexerSymbolIslands sym = 12 | match sym.Text with "" -> None | _ -> Some (sym.RightColumn, sym.Text.Split '.' |> Array.toList) 13 | 14 | // Parsing - find the identifier around the current location 15 | // (we look for full identifier in the backward direction, but only 16 | // for a short identifier forward - this means that when you hover 17 | // 'B' in 'A.B.C', you will get intellisense for 'A.B' module) 18 | let findIdents col lineStr lookupType = 19 | if lineStr = "" then None 20 | else 21 | Lexer.getSymbol lineStr 0 col lineStr lookupType [||] Lexer.singleLineQueryLexState 22 | |> Option.bind tryGetLexerSymbolIslands 23 | 24 | let findLongIdentsAndResidue (col, lineStr:string) = 25 | let lineStr = lineStr.Substring(0, col) 26 | 27 | match Lexer.getSymbol lineStr 0 col lineStr SymbolLookupKind.ByLongIdent [||] Lexer.singleLineQueryLexState with 28 | | Some sym -> 29 | match sym.Text with 30 | | "" -> [], "" 31 | | text -> 32 | let res = text.Split '.' |> List.ofArray |> List.rev 33 | if lineStr.[col - 1] = '.' then res |> List.rev, "" 34 | else 35 | match res with 36 | | head :: tail -> tail |> List.rev, head 37 | | [] -> [], "" 38 | | _ -> [], "" 39 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Shared/paket.references: -------------------------------------------------------------------------------- 1 | ExtCore 2 | FSharp.Compiler.Service 3 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/Checker.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System 3 | open System.IO 4 | open NUnit.Framework 5 | open FsUnit 6 | open System.Reflection 7 | open MonoDevelop.FSharp 8 | open MonoDevelop.Projects 9 | 10 | type TestPlatform = 11 | | Windows = 0 12 | | Mono = 1 13 | 14 | //[] 15 | type CompilerArgumentsTests() = 16 | 17 | member private x.``Run Only mscorlib referenced`` (assemblyName) = 18 | use testProject = Services.ProjectService.CreateDotNetProject ("F#") 19 | let assemblyName = match assemblyName with Fqn a -> fromFqn a | File a -> a 20 | let _ = testProject.AddReference assemblyName 21 | let references = 22 | CompilerArguments.generateReferences(testProject, 23 | Some (FSharpCompilerVersion.FSharp_3_1), 24 | FSharpTargetFramework.NET_4_5, 25 | ConfigurationSelector.Default, 26 | true) 27 | 28 | //there should be two references 29 | references.Length |> should equal 3 30 | 31 | //The two paths for mscorlib and FSharp.Core should match 32 | let makeTestableReference (path: string) = 33 | let path = path.Substring(4) 34 | let path = path.Substring(0,path.Length - 1) 35 | path 36 | let testPaths = references |> List.map makeTestableReference 37 | match testPaths |> List.map Path.GetDirectoryName with 38 | | [one; two; three] -> ()//one |> should equal three 39 | | _ -> Assert.Fail("Too many references returned") 40 | 41 | member private x.``Run Only FSharp.Core referenced``(assemblyName) = 42 | use testProject = Services.ProjectService.CreateDotNetProject ("F#") 43 | let assemblyName = match assemblyName with Fqn a -> fromFqn a | File a -> a 44 | let reference = testProject.AddReference assemblyName 45 | let references = 46 | CompilerArguments.generateReferences(testProject, 47 | Some (FSharpCompilerVersion.FSharp_3_1), 48 | FSharpTargetFramework.NET_4_5, 49 | ConfigurationSelector.Default, 50 | false) 51 | 52 | //there should be two references 53 | references.Length |> should equal 3 54 | 55 | //find the mscorlib inside the FSharp.Core ref 56 | let mscorlibContained = 57 | let assemblyDef = Mono.Cecil.AssemblyDefinition.ReadAssembly(reference.HintPath.ToString()) 58 | match assemblyDef.MainModule.AssemblyReferences |> Seq.tryFind (fun name -> name.Name = "mscorlib") with 59 | |Some name -> 60 | let resolved = assemblyDef.MainModule.AssemblyResolver.Resolve(name) 61 | Some(Path.neutralise resolved.MainModule.FullyQualifiedName) 62 | | None -> None 63 | 64 | //find the mscorlib from the returned references (removing unwanted chars "" / \ etc) 65 | let mscorlibReferenced = 66 | references 67 | |> List.tryFind (fun ref -> ref.Contains("mscorlib")) 68 | |> Option.map (fun r -> Path.neutralise (r.Replace("-r:", ""))) 69 | 70 | mscorlibContained |> should equal mscorlibReferenced 71 | 72 | //[] 73 | //[] 74 | //[] 75 | //[] 76 | [] 77 | member x.``Only mscorlib referenced`` (platform, assemblyName:string) = 78 | match platform with 79 | | TestPlatform.Mono when MonoDevelop.Core.Platform.IsWindows -> () 80 | | TestPlatform.Mono -> x.``Run Only mscorlib referenced`` (assemblyName) 81 | | TestPlatform.Windows when not MonoDevelop.Core.Platform.IsWindows -> () 82 | | TestPlatform.Windows -> x.``Run Only mscorlib referenced`` (assemblyName) 83 | | _ -> () 84 | 85 | 86 | //[] 87 | //[] 88 | //[] 89 | //[] 90 | //[] 91 | [] 92 | member x.``Only FSharp.Core referenced`` (platform: TestPlatform, assemblyName:string) = 93 | match platform with 94 | | TestPlatform.Mono when MonoDevelop.Core.Platform.IsWindows -> () 95 | | TestPlatform.Mono -> x.``Run Only FSharp.Core referenced``(assemblyName) 96 | | TestPlatform.Windows when not MonoDevelop.Core.Platform.IsWindows -> () 97 | | TestPlatform.Windows -> x.``Run Only FSharp.Core referenced``(assemblyName) 98 | | _ -> () 99 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/CompletionListsAdhocManualTests.fsx: -------------------------------------------------------------------------------- 1 | 2 | // This file is a set of manual tests you can run through to test the quality of 3 | // autocomplete, quick info and parameter info. 4 | 5 | 6 | open System 7 | 8 | open System // press '.' here. Only namespaces should appear. 9 | 10 | //---------------------------------------------------- 11 | // Check some basic completions and declaration lists 12 | 13 | System // press 'space' here 14 | 15 | System.Math.Max(3,4) // press '.' here 16 | 17 | System.Char 18 | 19 | System. 20 | List. 21 | System.Application 22 | System.Console.Wr // check formatting of description here 23 | 24 | let test1 (x: System.Applicati (* complete here *) ) = () 25 | 26 | Array.map 27 | 28 | List.a // Ctrl-space completion here 29 | 30 | System.C // Ctrl-space completion here 31 | 32 | //System.Math.Max(3,4).CompareTo // BUG press '(' here 33 | 34 | //---------------------------------------------------- 35 | // Check performance 36 | 37 | System // press '.' here - should be instantaneous 38 | 39 | System.Console.WriteLine // type through this line 40 | 41 | Microsoft.FSharp.Collections.Array.append // type through this line 42 | 43 | 44 | //------------------------------------------------------ 45 | // check that type providers give parameter info 46 | 47 | #r "/Users/tomaspetricek/Projects/GitHub/fsharp/FSharp.Data/bin/FSharp.Data.dll" 48 | 49 | type X = FSharp.Data.CsvProvider // press '<' here 50 | 51 | //------------------------------------------------------ 52 | // check parameter info 53 | 54 | Console.WriteLine // press '(' here, parameter/method/overloads info should appear 55 | b 56 | List.map // press '(' here, parameter/method info should appear 57 | 58 | Console.WriteLine(Console.WriteLine(), // press ',' here 59 | 60 | //------------------------------------------------------- 61 | // Check some experession typings 62 | 63 | 64 | ("") // press '.' here, expect string menu 65 | ("").Length // press '.' here, expect int32 menu 66 | 67 | let x = "" 68 | let y = (x) // press '.' here, expect string menu 69 | 70 | let a = (x). (* press '.' before here *) + (x) 71 | 72 | [] 73 | let main args = 74 | Console.WriteLine("Hello world!") 75 | 0 76 | 77 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/CompletionTests.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | 3 | open System 4 | open NUnit.Framework 5 | open MonoDevelop.FSharp 6 | open Mono.TextEditor 7 | open MonoDevelop.Ide.Editor 8 | open MonoDevelop.Ide.CodeCompletion 9 | open FsUnit 10 | open MonoDevelop 11 | 12 | type ``Completion Tests``() = 13 | let getParseResults (documentContext:DocumentContext, _text) = 14 | async { 15 | return documentContext.TryGetAst() 16 | } 17 | 18 | let getCompletions (input: string) = 19 | let offset = input.LastIndexOf "|" 20 | if offset = -1 then 21 | failwith "Input must contain a |" 22 | let input = input.Remove(offset, 1) 23 | let doc = TestHelpers.createDoc input "defined" 24 | let editor = doc.Editor 25 | editor.CaretOffset <- offset 26 | let ctx = new CodeCompletionContext() 27 | ctx.TriggerOffset <- offset 28 | let results = 29 | Completion.codeCompletionCommandImpl(editor, doc, ctx, false) 30 | |> Async.RunSynchronously 31 | |> Seq.map (fun c -> c.DisplayText) 32 | 33 | results |> Seq.toList 34 | 35 | [] 36 | member x.``Completes namespace``() = 37 | let results = getCompletions "open System.Text.|" 38 | results |> should contain "RegularExpressions" 39 | 40 | [] 41 | member x.``Completes local identifier``() = 42 | let results = getCompletions 43 | """ 44 | module mymodule = 45 | let completeme = 1 46 | let x = compl| 47 | """ 48 | 49 | results |> should contain "completeme" 50 | 51 | [] 52 | [] 53 | [] 54 | [] 55 | [] 56 | [] 57 | [] 58 | //[] 59 | [] 60 | [] 61 | [] 62 | [] 63 | [] 64 | [] 65 | [] 66 | member x.``Empty completions``(input: string) = 67 | let results = getCompletions input 68 | results |> should be Empty 69 | 70 | [] 71 | [] 72 | [] 73 | [] 74 | member x.``Not empty completions``(input: string) = 75 | let results = getCompletions input 76 | results |> shouldnot be Empty 77 | 78 | [] 79 | member x.``Keywords don't appear after dot``() = 80 | let results = getCompletions @"let x = string.l|" 81 | results |> shouldnot contain "let" 82 | 83 | [] 84 | member x.``Keywords appear after whitespace``() = 85 | let results = getCompletions @" l|" 86 | results |> should contain "let" 87 | 88 | [] 89 | member x.``Keywords appear at start of line``() = 90 | let results = getCompletions @" l|" 91 | results |> should contain "let" 92 | 93 | [] 94 | member x.``Keywords appear at column 0``() = 95 | let results = getCompletions @"o|" 96 | results |> should contain "open" 97 | 98 | [] 99 | member x.``Keywords can be parameters``() = 100 | let results = getCompletions @"let x = new System.IO.FileInfo(n|" 101 | results |> should contain "null" 102 | 103 | [] 104 | member x.``Completes modifiers``() = 105 | let results = getCompletions @"let mut|" 106 | results |> should contain "mutable" 107 | 108 | [] 109 | member x.``Completes lambda``() = 110 | let results = getCompletions @"let x = ""string"" |> Seq.map (fun c -> c.|" 111 | results |> should contain "ToString" 112 | results |> shouldnot contain "mutable" 113 | 114 | [] 115 | member x.``Completes local identifier with mismatched parens``() = 116 | let identifier = 1 117 | 118 | let results = getCompletions 119 | """ 120 | type rectangle(width, height) = 121 | class end 122 | 123 | module s = 124 | let height = 10 125 | let x = rectangle(he| 126 | """ 127 | results |> should contain "height" 128 | 129 | [] 130 | member x.``Completes attribute``() = 131 | let input = 132 | """ 133 | type TestAttribute() = 134 | inherit System.Attribute() 135 | 136 | type TestCaseAttribute() = 137 | inherit TestAttribute() 138 | [ should contain "Test" 142 | results |> should contain "TestCase" 143 | results |> shouldnot contain "Array" 144 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/DebuggerExpressionResolver.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System 3 | open NUnit.Framework 4 | open MonoDevelop.FSharp 5 | open FsUnit 6 | open MonoDevelop.Debugger 7 | 8 | [] 9 | type DebuggerExpressionResolver() = 10 | 11 | let content = 12 | """ 13 | type TestOne() = 14 | member val PropertyOne = "42" with get, set 15 | member x.FunctionOne(parameter) = () 16 | 17 | let local|One = TestOne() 18 | let local|Two = localOne.Prope|rtyOne 19 | let localThree = local|One.PropertyOne 20 | let localFour = localOne.Property|One""" 21 | 22 | let getOffset expr = 23 | let startOffset = content.IndexOf (expr, StringComparison.Ordinal) 24 | let previousMarkers = 25 | content 26 | |> String.toArray 27 | |> Array.findIndices((=) '|') 28 | |> Array.filter(fun i -> i < startOffset-1) 29 | |> Array.length 30 | let offset = content.IndexOf('|',startOffset) - previousMarkers 31 | offset 32 | 33 | let resolveExpression (doc:TestDocument, content:string, offset:int) = 34 | let resolver = new FSharpDebuggerExpressionResolver() :> IDebuggerExpressionResolver 35 | Async.AwaitTask (resolver.ResolveExpressionAsync(doc.Editor, doc, offset, Async.DefaultCancellationToken)) 36 | |> Async.RunSynchronously 37 | 38 | [] 39 | [] 40 | [] 41 | [] 42 | [] 43 | member x.TestBasicLocalVariable(localVariable, expected) = 44 | let basicOffset = getOffset (localVariable) 45 | let doc = TestHelpers.createDoc (content.Replace("|" ,"")) "" 46 | 47 | let loc = doc.Editor.OffsetToLocation basicOffset 48 | let lineTxt = doc.Editor.GetLineText(loc.Line, false) 49 | let markedLine = (String.replicate loc.Column " " + "^" ) 50 | System.Console.WriteLine(sprintf "%s\n%s" lineTxt markedLine) 51 | 52 | let debugDataTipInfo = resolveExpression (doc, content, basicOffset) 53 | debugDataTipInfo.Text |> should equal expected 54 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/FSharpUnitTestTextEditorExtensionTests.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System 3 | open NUnit.Framework 4 | open MonoDevelop.FSharp 5 | open FsUnit 6 | 7 | [] 8 | type FSharpUnitTestTextEditorExtensionTests() = 9 | let gatherTests (text:string) = 10 | let editor = TestHelpers.createDoc text "" 11 | let ast = editor.Ast 12 | let symbols = ast.GetAllUsesOfAllSymbolsInFile() |> Async.RunSynchronously 13 | 14 | unitTestGatherer.gatherUnitTests (editor.Editor, symbols) 15 | |> Seq.toList 16 | 17 | let gatherTestsWithReference (text:string) = 18 | let attributes = """ 19 | namespace NUnit.Framework 20 | open System 21 | type TestAttribute = 22 | inherit Attribute 23 | new() = { inherit Attribute() } 24 | new(name) = { inherit Attribute() } 25 | type TestFixtureAttribute() = 26 | inherit Attribute() 27 | type IgnoreAttribute() = 28 | inherit Attribute() 29 | type TestCaseAttribute = 30 | inherit TestAttribute 31 | new() = { inherit Attribute() } 32 | new(name) = { inherit Attribute() } 33 | """ 34 | gatherTests (attributes + text) 35 | 36 | [] 37 | member x.BasicTestCoveringNormalAndDoubleQuotedTestsInATestFixture () = 38 | let normalAndDoubleTick = """ 39 | open System 40 | open NUnit.Framework 41 | [] 42 | type Test() = 43 | [] 44 | member x.TestOne() = () 45 | 46 | [] 47 | [] 48 | member x.``Test Two``() = () 49 | """ 50 | let res = gatherTestsWithReference normalAndDoubleTick 51 | match res with 52 | | [fixture;t1;t2] -> 53 | fixture.IsFixture |> should equal true 54 | fixture.UnitTestIdentifier |> should equal "NUnit.Framework.Test" 55 | 56 | t1.UnitTestIdentifier |> should equal "NUnit.Framework.Test.TestOne" 57 | t1.IsIgnored |> should equal false 58 | 59 | t2.UnitTestIdentifier |> should equal "NUnit.Framework.Test.``Test Two``" 60 | t2.IsIgnored |> should equal true 61 | | _ -> NUnit.Framework.Assert.Fail "invalid number of tests returned" 62 | 63 | [] 64 | member x.NoTests () = 65 | let noTests = """ 66 | open System 67 | open NUnit.Framework 68 | 69 | type Test() = 70 | member x.TestOne() = () 71 | """ 72 | 73 | let tests = gatherTestsWithReference noTests 74 | tests.Length |> should equal 0 75 | 76 | [] 77 | member x.``Module tests without TestFixtureAttribute are detected`` () = 78 | let noTests = """ 79 | module someModule = 80 | 81 | open NUnit.Framework 82 | 83 | [] 84 | let atest () = 85 | () 86 | """ 87 | 88 | let tests = gatherTestsWithReference noTests 89 | tests.Length |> should equal 1 90 | 91 | [] 92 | member x.NestedTestCoveringNormalAndDoubleQuotedTestsInATestFixture () = 93 | let nestedTests = """ 94 | open System 95 | open NUnit.Framework 96 | module Test = 97 | [] 98 | type Test() = 99 | [] 100 | member x.TestOne() = () 101 | 102 | [] 103 | [] 104 | member x.``Test Two``() = () 105 | """ 106 | let tests = gatherTestsWithReference nestedTests 107 | 108 | match tests with 109 | | [fixture;t1;t2] -> 110 | fixture.IsFixture |> should equal true 111 | fixture.UnitTestIdentifier |> should equal "NUnit.Framework.Test+Test" 112 | 113 | t1.UnitTestIdentifier |> should equal "NUnit.Framework.Test+Test.TestOne" 114 | t1.IsIgnored |> should equal false 115 | 116 | t2.UnitTestIdentifier |> should equal "NUnit.Framework.Test+Test.``Test Two``" 117 | t2.IsIgnored |> should equal true 118 | | _ -> NUnit.Framework.Assert.Fail "invalid number of tests returned" 119 | 120 | [] 121 | member x.TestsPresentButNoNUnitReference () = 122 | let normalAndDoubleTick = """ 123 | open System 124 | open NUnit.Framework 125 | [] 126 | type Test() = 127 | [] 128 | member x.TestOne() = () 129 | 130 | [] 131 | [] 132 | member x.``Test Two``() = () 133 | """ 134 | let tests = gatherTests normalAndDoubleTick 135 | 136 | tests.Length |> should equal 0 137 | 138 | [] 139 | member x.``Test cases`` () = 140 | let nestedTests = """ 141 | open System 142 | open NUnit.Framework 143 | module Test = 144 | [] 145 | type Test() = 146 | [] 147 | member x.TestOne(s:string) = () 148 | """ 149 | let tests = gatherTestsWithReference nestedTests 150 | 151 | match tests with 152 | | [fixture;t1] -> 153 | t1.UnitTestIdentifier |> should equal "NUnit.Framework.Test+Test.TestOne" 154 | t1.IsIgnored |> should equal false 155 | | _ -> NUnit.Framework.Assert.Fail "invalid number of tests returned" -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/GlobalSearch.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System.Collections.Generic 3 | open Microsoft.FSharp.Compiler.SourceCodeServices 4 | open NUnit.Framework 5 | open FsUnit 6 | open MonoDevelop.FSharp 7 | 8 | [] 9 | type TestGlobalSearch() = 10 | 11 | 12 | let input = """ 13 | module Test 14 | let (++) a b = a + b 15 | let (|Full|Empty|) x = if x = "" then Empty else Full 16 | type MyRecord = {Test : int} 17 | type MyType() = 18 | member x.Foo = 42 19 | member x.Bar() = 43 20 | type MyUnion = First of int 21 | 22 | [] 23 | type MyPoint3D = 24 | val x: float 25 | val y: float 26 | val z: float 27 | 28 | type IMyInterface = 29 | abstract member Test : int -> int 30 | 31 | type MyEnum = First = 1 | Second = 2 32 | 33 | type MyDelegate = delegate of (int * int) -> int 34 | """ 35 | let searchByTag tag = 36 | match TestHelpers.getAllSymbols input with 37 | | Some xs -> 38 | let tags = Search.byTag tag xs 39 | tags 40 | |> Seq.map(fun s -> s.Symbol.DisplayName) 41 | |> Seq.toList 42 | | _ -> [] 43 | 44 | [] 45 | member x.Operators_Can_Be_Filtered() = 46 | searchByTag "op" |> shouldEqual ["( + )"; "( ++ )"; "( = )"] // ( + ) and ( = ) aren't user defined operators 47 | 48 | [] 49 | member x.ActivePatterns_Can_Be_Filtered() = 50 | searchByTag "ap" |> shouldEqual ["( |Full|Empty| )"] 51 | 52 | [] 53 | member x.Records_Can_Be_Filtered() = 54 | searchByTag "r" |> shouldEqual ["MyRecord"] 55 | 56 | [] 57 | [] 58 | [] 59 | member x.Types_Can_Be_Filtered(search) = 60 | searchByTag search |> shouldEqual ["MyType"; "StructAttribute"; "StructAttribute"] // needs fixing 61 | 62 | [] 63 | member x.Unions_Can_Be_Filtered() = 64 | searchByTag "u" |> shouldEqual ["MyUnion"] 65 | 66 | [] 67 | member x.Modules_Can_Be_Filtered() = 68 | searchByTag "mod" |> shouldEqual ["Test"] 69 | 70 | [] 71 | member x.Structs_Can_Be_Filtered() = 72 | searchByTag "s" |> shouldEqual ["MyPoint3D"] 73 | 74 | [] 75 | member x.Interfaces_Can_Be_Filtered() = 76 | searchByTag "i" |> shouldEqual ["IMyInterface"] 77 | 78 | [] 79 | member x.Enums_Can_Be_Filtered() = 80 | searchByTag "e" |> shouldEqual ["MyEnum"] 81 | 82 | [] 83 | member x.Properties_Can_Be_Filtered() = 84 | searchByTag "p" |> shouldEqual ["Foo"] 85 | 86 | [] 87 | member x.Members_Can_Be_Filtered() = 88 | searchByTag "m" |> shouldEqual ["Bar"; "Test"; "Invoke"] //Invoke? 89 | 90 | [] 91 | member x.Fields_Can_Be_Filtered() = 92 | searchByTag "f" |> shouldEqual ["Test"; "x"; "y"; "z"; "First"; "Second"] //Test? 93 | 94 | [] 95 | member x.Delegates_Can_Be_Filtered() = 96 | searchByTag "d" |> shouldEqual ["MyDelegate"] 97 | 98 | [] 99 | member x.Search_By_Unique_Pattern_Is_Correct() = 100 | match TestHelpers.getAllSymbols input with 101 | | Some xs -> 102 | let result = 103 | Search.byPattern (Dictionary<_,_>()) "++" xs 104 | |> Seq.map (fun (a, b) -> a.Symbol.DisplayName ) 105 | |> Seq.toList 106 | result |> shouldEqual ["( ++ )"] 107 | | _ -> Assert.Fail "Not found" 108 | 109 | [] 110 | member x.Search_By_Pattern_Is_Correct() = 111 | match TestHelpers.getAllSymbols input with 112 | | Some xs -> 113 | let result = Search.byPattern (Dictionary<_,_>()) "My" xs 114 | 115 | result 116 | |> Seq.map (fun (a, b) -> a.Symbol.DisplayName, a.Symbol.GetType() ) 117 | |> Seq.toList 118 | |> shouldEqual 119 | [ "MyRecord", typeof 120 | "MyType", typeof 121 | "( .ctor )", typeof 122 | "MyUnion", typeof 123 | "MyPoint3D", typeof 124 | "IMyInterface", typeof 125 | "MyEnum", typeof 126 | "MyDelegate", typeof ] 127 | | _ -> Assert.Fail "Not found" 128 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/HighlightUsagesTests.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System.Text.RegularExpressions 3 | open System.Threading 4 | open NUnit.Framework 5 | open FsUnit 6 | open MonoDevelop.FSharp.MonoDevelop 7 | open MonoDevelop.FSharp 8 | open ExtCore 9 | open ExtCore.Control 10 | open ExtCore.Control.Collections 11 | [] 12 | type HighlightUsagesTests() = 13 | let assertUsages (source:string, expectedCount) = 14 | let offset = source.IndexOf "|" 15 | let source = source.Replace("|", "") 16 | let doc = TestHelpers.createDoc source "" 17 | let line, col, lineStr = doc.Editor.GetLineInfoFromOffset offset 18 | //doc.Ast 19 | 20 | match Parsing.findIdents col lineStr SymbolLookupKind.ByLongIdent with 21 | | None -> Assert.Fail "Could not find ident" 22 | | Some(colu, ident) -> let symbolUse = doc.Ast.GetSymbolAtLocation(line, col, lineStr) |> Async.RunSynchronously 23 | match symbolUse with 24 | | Some symbol -> 25 | let references = doc.Ast.GetUsesOfSymbolInFile(symbol.Symbol) |> Async.RunSynchronously 26 | references.Length |> should equal expectedCount 27 | | None -> Assert.Fail "No symbol found" 28 | 29 | [] 30 | member x.``Highlight usages from declaration``() = 31 | let source = 32 | """ 33 | let ast|ring = "astring" 34 | let b = astring 35 | """ 36 | assertUsages(source, 2) 37 | 38 | [] 39 | member x.``Highlight usages from usage``() = 40 | let source = 41 | """ 42 | let astring = "astring" 43 | let b = astr|ing 44 | """ 45 | assertUsages(source, 2) 46 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/IndentationTrackerTests.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open NUnit.Framework 3 | open MonoDevelop.FSharp 4 | open FsUnit 5 | open Mono.TextEditor 6 | 7 | [] 8 | type IndentationTrackerTests() = 9 | 10 | let docWithCaretAt (content:string) = 11 | let d = TestHelpers.createDoc(content.Replace("§", "")) "" 12 | d.Editor.SetIndentationTracker (new FSharpIndentationTracker(d.Editor)) 13 | do match content.IndexOf('§') with 14 | | -1 -> () 15 | | x -> let l = d.Editor.OffsetToLocation(x) 16 | d.Editor.SetCaretLocation(l.Line, l.Column) 17 | d 18 | 19 | let getIndent (content:string) = 20 | let doc = docWithCaretAt content 21 | let tracker = FSharpIndentationTracker(doc.Editor) 22 | let caretLine = doc.Editor.CaretLine 23 | tracker.GetIndentationString(caretLine).Length 24 | 25 | let insertEnterAtSection (text:string) = 26 | let idx = text.IndexOf ('§') 27 | let doc = TextDocument(text.Replace("§", "")) 28 | use data = new TextEditorData (doc) 29 | data.Caret.Offset <- idx 30 | MiscActions.InsertNewLine(data) 31 | data.Document.Text 32 | 33 | [] 34 | member x.``Basic indents``() = 35 | let getIndent (doc:TestDocument, line:int, col) = 36 | doc.Editor.SetCaretLocation (2, 2) 37 | let column = doc.Editor.GetVirtualIndentationColumn (line) 38 | column 39 | 40 | let doc = "" |> TestHelpers.createDoc """ 41 | let a = 42 | 43 | let b = (fun a -> 44 | 45 | let b = a 46 | """ 47 | doc.Editor.SetIndentationTracker (FSharpIndentationTracker(doc.Editor)) 48 | getIndent (doc, 3, 1) |> should equal 5 49 | getIndent (doc, 5, 1) |> should equal 5 50 | getIndent (doc, 7, 1) |> should equal 3 51 | 52 | [] 53 | member x.``Match expression``() = 54 | getIndent("let m = match 123 with\n§") |> should equal 8 55 | 56 | [] 57 | member x.``If then expression``() = 58 | getIndent("if true then\n§") |> should equal 4 59 | 60 | [] 61 | member x.``Indented match expression``() = 62 | getIndent("""let m = 63 | match 123 with 64 | §""") |> should equal 3 65 | 66 | [] 67 | member x.``Enter doesnt change indentation at indent position``() = 68 | let input = """ let a = 123 69 | §let c = 321""" 70 | input 71 | |> insertEnterAtSection 72 | |> should equal @" let a = 123 73 | 74 | let c = 321" 75 | 76 | [] 77 | member x.``Enter after equals indents``() = 78 | let input = """ let a = §123""" 79 | input 80 | |> insertEnterAtSection 81 | |> shouldEqualIgnoringLineEndings """ let a = 82 | 123""" 83 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/ParameterHinting.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | 3 | open System 4 | open NUnit.Framework 5 | open NUnit.Framework.Extensibility 6 | open MonoDevelop.FSharp 7 | open Mono.TextEditor 8 | open MonoDevelop.Ide.Editor 9 | open MonoDevelop.Ide.CodeCompletion 10 | open FsUnit 11 | open MonoDevelop 12 | 13 | type ``Parameter Hinting``() = 14 | let getHints (input: string) = 15 | let offset = input.LastIndexOf "|" 16 | if offset = -1 then 17 | failwith "Input must contain a |" 18 | let input = input.Remove(offset, 1) 19 | let doc = TestHelpers.createDoc input "defined" 20 | let editor = doc.Editor 21 | editor.CaretOffset <- offset 22 | let ctx = new CodeCompletionContext() 23 | ctx.TriggerOffset <- offset 24 | 25 | let index = ParameterHinting.getParameterIndex(editor, editor.Text.LastIndexOf("(")) 26 | let hints = ParameterHinting.getHints(editor, doc, ctx) 27 | |> Async.RunSynchronously 28 | hints.[0].GetParameterName(index - 1) // index is 1 based 29 | 30 | [] 31 | [] 32 | [] 33 | [] 34 | [] 35 | member x.``Parameter hinting``(input, expected) = 36 | getHints input |> should equal expected 37 | 38 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/ParsingTests.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open NUnit.Framework 3 | open FsUnit 4 | open MonoDevelop.FSharp 5 | open ExtCore 6 | 7 | 8 | [] 9 | type ParsingTests() = 10 | let checkGetSymbol col lineStr expected expectedColumn = 11 | let expected = if expected = "" then [] else expected.Split '.' |> Array.toList 12 | match Parsing.findIdents col lineStr SymbolLookupKind.ByLongIdent 13 | |> Option.orTry (fun () -> Parsing.findIdents col lineStr SymbolLookupKind.Fuzzy) with 14 | | Some(colu, ident) -> ident |> should equal expected 15 | colu |> should equal expectedColumn 16 | | None -> Assert.Fail "Could not find ident" 17 | 18 | let assertIdents (source: string) expected expectedColumn = 19 | let col = source.IndexOf "|" 20 | let source = source.Replace("|", "") 21 | checkGetSymbol col source expected expectedColumn 22 | 23 | let assertLongIdentsAndResidue (source: string) expectedIdent expectedResidue = 24 | let col = source.IndexOf "|" 25 | let source = source.Replace("|", "") 26 | let ident, residue = Parsing.findLongIdentsAndResidue(col, source) 27 | let expectedIdent = if expectedIdent = "" then [] else expectedIdent.Split '.' 28 | |> Array.toList 29 | ident |> should equal expectedIdent 30 | residue |> should equal expectedResidue 31 | 32 | let assertResidue (source: string) expectedResidue = 33 | let col = source.IndexOf "|" 34 | let source = source.Replace("|", "") 35 | let residue = Parsing.findResidue(col, source) 36 | residue |> should equal expectedResidue 37 | 38 | [] 39 | [] 40 | [] 41 | [] 42 | member x.``Find long idents``(source: string, expected, expectedColumn) = 43 | assertIdents source expected expectedColumn 44 | 45 | [] 46 | [] 47 | [] 48 | [] 49 | [] 50 | [] 51 | [] 52 | member x.``Find long idents and residue``(source: string, expectedIdent, expectedResidue) = 53 | assertLongIdentsAndResidue source expectedIdent expectedResidue 54 | 55 | [] 56 | member x.``Find residue``(source: string, expectedResidue) = 57 | assertResidue source expectedResidue 58 | 59 | [] 60 | member x.``Find custom operator``() = 61 | let source = "let ( >|.> ) a b = a + b" 62 | assertIdents source ">.>" 9 63 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/ProjectCracking.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open FsUnit 3 | open NUnit.Framework 4 | open MonoDevelop.Core 5 | open MonoDevelop.Core.ProgressMonitoring 6 | open MonoDevelop.Projects 7 | open MonoDevelop.Projects.MSBuild 8 | open System 9 | open MonoDevelop.FSharp 10 | 11 | [] 12 | type ProjectCracking() = 13 | let fsproj = "/Users/jason/src/monodevelop/main/external/fsharpbinding/MonoDevelop.FSharpBinding/MonoDevelop.FSharp.fsproj" 14 | 15 | [] 16 | member x.``Can crack fsharpbinding project``() = 17 | Environment.SetEnvironmentVariable ("MONO_ADDINS_REGISTRY", "/tmp") 18 | Environment.SetEnvironmentVariable ("XDG_CONFIG_HOME", "/tmp") 19 | Runtime.Initialize (true) 20 | MonoDevelop.Ide.DesktopService.Initialize() 21 | let sln = "/Users/jason/src/monodevelop/main/external/fsharpbinding/MonoDevelop.FSharp.sln" 22 | let monitor = new ConsoleProgressMonitor() 23 | let w = Services.ProjectService.ReadWorkspaceItem (monitor, FilePath(sln)) 24 | |> Async.AwaitTask 25 | |> Async.RunSynchronously 26 | 27 | let s = w :?> Solution 28 | let fsproj = s.Items.[0] :?> DotNetProject 29 | let opts = languageService.GetProjectOptionsFromProjectFile fsproj 30 | printfn "%A" opts -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/ProjectTests.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open NUnit.Framework 3 | open FsUnit 4 | open MonoDevelop.Core 5 | open MonoDevelop.FSharp 6 | open MonoDevelop.Ide 7 | open MonoDevelop.Ide.Gui.Components 8 | open MonoDevelop.Projects 9 | open System 10 | open System.IO 11 | 12 | [] 13 | type ProjectTests() = 14 | 15 | [] 16 | member this.Can_reorder_nodes() = 17 | if not MonoDevelop.Core.Platform.IsWindows then 18 | let xml = 19 | """ 20 | 21 | 22 | 23 | 24 | 25 | 26 | """ 27 | let path = Path.GetTempPath() + Guid.NewGuid().ToString() + ".fsproj" 28 | File.WriteAllText (path, xml) 29 | let project = Services.ProjectService.CreateDotNetProject ("F#") 30 | project.FileName <- new FilePath(path) 31 | let movingNode = project.AddFile("test1.fs") 32 | let moveToNode = project.AddFile("test2.fs") 33 | 34 | let fsp = new FSharpProjectNodeCommandHandler() 35 | fsp.MoveNodes moveToNode movingNode DropPosition.After 36 | 37 | let newXml = File.ReadAllText path 38 | let expected = 39 | """ 40 | 41 | 42 | 43 | 44 | """ 45 | newXml |> should equal expected 46 | 47 | [] 48 | member this.``Adds desktop conditional FSharp targets``() = 49 | if not MonoDevelop.Core.Platform.IsWindows then 50 | let project = Services.ProjectService.CreateDotNetProject ("F#") :?> FSharpProject 51 | Project.addConditionalTargets project.MSBuildProject 52 | let s = project.MSBuildProject.SaveToString() 53 | s |> shouldEqualIgnoringLineEndings 54 | """ 55 | 56 | 57 | 58 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 59 | 60 | 61 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 62 | 63 | """ 64 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/Script.fsx: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/SemanticHighlighting.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | 3 | open System 4 | open Microsoft.FSharp.Compiler.SourceCodeServices 5 | open NUnit.Framework 6 | open MonoDevelop.FSharp 7 | open MonoDevelop.Ide.Editor 8 | open Mono.TextEditor.Highlighting 9 | open FsUnit 10 | 11 | [] 12 | type SemanticHighlighting() = 13 | let defaultStyles = SyntaxModeService.DefaultColorStyle 14 | let getStyle (content : string) = 15 | let fixedc = content.Replace("§", "") 16 | let doc = TestHelpers.createDoc fixedc "defined" 17 | let style = SyntaxModeService.GetColorStyle "Gruvbox" 18 | let tsc = SyntaxMode.tryGetTokensSymbolsAndColours doc 19 | 20 | let segments = 21 | doc.Editor.GetLines() 22 | |> Seq.map (fun line -> SyntaxMode.getColouredSegment tsc line.LineNumber line.Offset (doc.Editor.GetLineText line) style) 23 | 24 | for line in segments do 25 | line |> Seq.toList |> List.rev |> List.iteri (fun i seg -> 26 | printfn """%s"%s" Style:%s S:%i E:%i L:%i""" 27 | (String.replicate i " ") 28 | (doc.Editor.GetTextBetween(seg.Offset, seg.EndOffset)) 29 | seg.ColorStyleKey 30 | seg.Offset 31 | seg.EndOffset 32 | seg.Length ) 33 | printfn "\n" 34 | 35 | let offset = content.IndexOf("§") 36 | let endOffset = content.LastIndexOf("§") - 1 37 | let segment = segments |> Seq.concat |> Seq.tryFind (fun s -> s.Offset = offset && s.EndOffset = endOffset) 38 | match segment with 39 | | Some(s) -> s.ColorStyleKey 40 | | _ -> "segment not found" 41 | 42 | [] 43 | member x.Undefined_IfDef() = 44 | let content =""" 45 | #if undefined 46 | let sub = (-) 47 | §let§ add = (+) 48 | #endif""" 49 | getStyle content |> should equal "Excluded Code" 50 | 51 | [] 52 | member x.Module_is_highlighted() = 53 | let content = """ 54 | module MyModule = 55 | let someFunc() = () 56 | 57 | module Consumer = 58 | §MyModule§.someFunc()""" 59 | let output = getStyle content 60 | output |> should equal "User Types" 61 | 62 | [] 63 | member x.Type_is_highlighted() = 64 | let content = """ 65 | open System 66 | 67 | module MyModule = 68 | let guid = §Guid§.NewGuid()""" 69 | let output = getStyle content 70 | output |> should equal "User Types(Value types)" 71 | 72 | [] 73 | member x.Add_is_plain_text() = 74 | let content = "let §add§ = (+)" 75 | getStyle content |> should equal "User Method Declaration" 76 | 77 | [] 78 | [] 79 | member x.Semantic_highlighting(source, expectedStyle) = 80 | getStyle source |> should equal expectedStyle 81 | 82 | [] 83 | member x.Generics_are_highlighted() = 84 | let content = """ 85 | type Class<§'a§>() = class end 86 | let _ = new Class<_>()""" 87 | let output = getStyle content 88 | output |> should equal defaultStyles.UserTypesTypeParameters.Name 89 | 90 | [] 91 | member x.Type_constraints_are_highlighted() = 92 | let content = """type Constrained<'a when §'a§ :> IDisposable> = class end""" 93 | let output = getStyle content 94 | output |> should equal defaultStyles.UserTypesTypeParameters.Name 95 | 96 | [] 97 | member x.Static_inlined_type_constraints_are_highlighted() = 98 | let content = """let inline test (x: §^a§) (y: ^b) = x + y""" 99 | let output = getStyle content 100 | output |> should equal defaultStyles.UserTypesTypeParameters.Name -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/SyntaxHighlighting.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | 3 | open System 4 | open NUnit.Framework 5 | open MonoDevelop.FSharp 6 | open Mono.TextEditor 7 | open Mono.TextEditor.Highlighting 8 | open MonoDevelop.Ide.Editor 9 | open FsUnit 10 | 11 | [] 12 | type SyntaxHighlighting() = 13 | let assertStyle (input:string, expectedStyle:string) = 14 | let offset = input.IndexOf("§") 15 | let length = input.LastIndexOf("§") - offset - 1 16 | let input = input.Replace("§", "") 17 | let data = new TextEditorData (new TextDocument (input)) 18 | let syntaxMode = SyntaxModeService.GetSyntaxMode (data.Document, "text/x-fsharp") 19 | let style = SyntaxModeService.GetColorStyle ("Gruvbox") 20 | let line = data.Lines |> Seq.head 21 | let chunks = syntaxMode.GetChunks(style, line, offset, line.Length) 22 | let chunk = chunks |> Seq.tryFind (fun c -> c.Offset = offset && c.Length = length) 23 | 24 | match chunk with 25 | | Some (c) -> c.Style |> should equal expectedStyle 26 | | _ -> printfn "Offset - %d, Length - %d" offset length 27 | printfn "%A" chunks 28 | Assert.Fail() 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 | [ §ignore§", "User Method Declaration")>] 61 | [] 62 | [] 63 | [] 64 | [ §should equal", "Plain Text")>] 65 | [ §should§ equal", "User Method Declaration")>] 66 | [] 67 | [", "Plain Text")>] 68 | [] 69 | [] 70 | [] 71 | [] 72 | [] 73 | [] 74 | [] 75 | [] 76 | [] 77 | [ ", "User Field Declaration")>] 78 | [] 79 | [] 80 | [ §SomeType§", "User Types")>] 81 | [] 82 | [] 83 | [] 84 | [] 85 | [] 86 | [] 87 | [] 88 | [] 89 | [] 90 | [>§", "Punctuation(Brackets)")>] 91 | [] 92 | [] 93 | [] 94 | [] 95 | [§ Option.bind", "Punctuation(Brackets)")>] 96 | [", "User Field Declaration")>] 97 | [] 98 | [] 99 | [] 100 | [] 101 | [", "User Field Declaration")>] 102 | [] 103 | [(§fun e", "Punctuation(Brackets)")>] 104 | [] 105 | [] 106 | [] 107 | [] 108 | [] 109 | [] 110 | [] 111 | [] 112 | member x.``Syntax highlighting``(source, expectedStyle) = 113 | assertStyle (source, expectedStyle) 114 | 115 | [] 116 | [] 117 | [ §^T§ :", "User Types")>] 118 | [ §seq§<'T>", "User Types")>] 119 | [] 120 | 121 | member x.``Tooltip highlighting``(source, expectedStyle) = 122 | assertStyle (source, expectedStyle) 123 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/TestBase.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System 3 | open System.Reflection 4 | open System.IO 5 | open NUnit.Framework 6 | 7 | module FsUnit = 8 | 9 | open System.Diagnostics 10 | open NUnit.Framework 11 | open NUnit.Framework.Constraints 12 | 13 | [] 14 | let should (f : 'a -> #Constraint) x (y : obj) = 15 | let c = f x 16 | let y = 17 | match y with 18 | | :? (unit -> unit) -> box (new TestDelegate(y :?> unit -> unit)) 19 | | _ -> y 20 | Assert.That(y, c) 21 | 22 | let shouldnot (f : 'a -> #Constraint) x (y : obj) = 23 | let c = f x 24 | let y = 25 | match y with 26 | | :? (unit -> unit) -> box (new TestDelegate(y :?> unit -> unit)) 27 | | _ -> y 28 | Assert.That(y, new NotConstraint(c)) 29 | 30 | let equal x = new EqualConstraint(x) 31 | 32 | // like "should equal", but validates same-type 33 | let shouldEqual (x: 'a) (y: 'a) = Assert.AreEqual(x, y, sprintf "Expected: %A\nActual: %A" x y) 34 | let replaceLineEnding (s:string) = 35 | s.Replace("\r\n", "\n") 36 | 37 | let shouldEqualIgnoringLineEndings (x: string) (y: string) = 38 | Assert.AreEqual((replaceLineEnding x), (replaceLineEnding y), sprintf "Expected: %A\nActual: %A" x y) 39 | 40 | let notEqual x = new NotConstraint(new EqualConstraint(x)) 41 | 42 | let NOT c = new NotConstraint(c) 43 | 44 | let contain x = new ContainsConstraint(x) 45 | 46 | let haveLength n = Has.Length.EqualTo(n) 47 | 48 | let haveCount n = Has.Count.EqualTo(n) 49 | 50 | let NotEmpty = Has.Length.GreaterThan(0) 51 | 52 | let endWith (s:string) = new EndsWithConstraint(s) 53 | 54 | let startWith (s:string) = new StartsWithConstraint(s) 55 | 56 | let be = id 57 | 58 | let Null = new NullConstraint() 59 | 60 | let Empty = new EmptyConstraint() 61 | 62 | let EmptyString = new EmptyStringConstraint() 63 | 64 | let NullOrEmptyString = new NullOrEmptyStringConstraint() 65 | 66 | let True = new TrueConstraint() 67 | 68 | let False = new FalseConstraint() 69 | 70 | let sameAs x = new SameAsConstraint(x) 71 | 72 | let throw = Throws.TypeOf 73 | 74 | 75 | [] 76 | module Path = 77 | let (++) (a:string) (b:string) = Path.Combine(a,b) 78 | ///Cleans up a path removing trailing double quotes and also consistant forward slash handling 79 | let neutralise (path:string) = 80 | Path.GetFullPath( path.TrimStart('\"').TrimEnd('\"')) 81 | 82 | 83 | [] 84 | module AssemblyLocation = 85 | let fromFqn (fqn:string) = 86 | let assembly = Assembly.ReflectionOnlyLoad fqn 87 | assembly.Location 88 | 89 | let (|Fqn|File|) (input:string) = 90 | if input.Contains "," then Fqn(input) 91 | else File(input) 92 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/TestDocument.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | 3 | open MonoDevelop.FSharp 4 | open MonoDevelop.Ide.Editor 5 | open System.Threading.Tasks 6 | 7 | type TestDocument(name, parsedDocument, editor: TextEditor) = 8 | inherit DocumentContext() 9 | 10 | override x.Name = name 11 | override x.Project = null 12 | override x.AnalysisDocument = null 13 | override x.ParsedDocument = parsedDocument 14 | override x.AttachToProject(_) = () 15 | override x.ReparseDocument() = () 16 | override x.GetOptionSet() = null 17 | override x.UpdateParseDocument() = Task.FromResult parsedDocument 18 | member x.Editor = editor 19 | member x.Ast = parsedDocument.Ast :?> ParseAndCheckResults 20 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/TestHelpers.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System 3 | open Microsoft.FSharp.Compiler.SourceCodeServices 4 | open MonoDevelop.FSharp 5 | open MonoDevelop.Ide.Editor 6 | open MonoDevelop.Ide.TypeSystem 7 | open MonoDevelop.Core 8 | open MonoDevelop.Core.Text 9 | 10 | type FixtureSetup() = 11 | static let firstRun = ref true 12 | 13 | member x.Initialise() = 14 | if !firstRun then 15 | firstRun := false 16 | MonoDevelop.FSharp.MDLanguageService.DisableVirtualFileSystem() 17 | MonoDevelop.Ide.DesktopService.Initialize() 18 | 19 | GuiUnit.TestRunner.ExitCode |> ignore // hack to get GuiUnit into the AppDomain 20 | 21 | module TestHelpers = 22 | let filename = if Platform.IsWindows then "c:\\test.fsx" else "test.fsx" 23 | 24 | let parseAndCheckFile source = 25 | async { 26 | try 27 | let checker = FSharpChecker.Create() 28 | let! projOptions = checker.GetProjectOptionsFromScript(filename, source) 29 | let! parseResults, checkAnswer = checker.ParseAndCheckFileInProject(filename, 0, source , projOptions) 30 | 31 | // Construct new typed parse result if the task succeeded 32 | let results = 33 | match checkAnswer with 34 | | FSharpCheckFileAnswer.Succeeded(checkResults) -> 35 | ParseAndCheckResults(Some checkResults, Some parseResults) 36 | | FSharpCheckFileAnswer.Aborted -> 37 | ParseAndCheckResults(None, Some parseResults) 38 | 39 | return results 40 | with exn -> 41 | printf "%A" exn 42 | return ParseAndCheckResults(None, None) } 43 | 44 | let createDoc source compilerDefines = 45 | FixtureSetup().Initialise() 46 | 47 | let results = parseAndCheckFile source |> Async.RunSynchronously 48 | let options = ParseOptions(FileName = filename, Content = StringTextSource(source)) 49 | 50 | let parsedDocument = 51 | ParsedDocument.create options results [compilerDefines] (Some (new DocumentLocation(0,0))) |> Async.RunSynchronously 52 | 53 | let doc = TextEditorFactory.CreateNewReadonlyDocument(StringTextSource(source), filename, "text/fsharp") 54 | let editor = MonoDevelop.Ide.Editor.TextEditorFactory.CreateNewEditor (doc) 55 | 56 | TestDocument(filename, parsedDocument, editor) 57 | 58 | let getAllSymbols source = 59 | async { 60 | let! results = parseAndCheckFile source 61 | return! results.GetAllUsesOfAllSymbolsInFile() 62 | } |> Async.RunSynchronously 63 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/TestViewContent.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System 3 | open System.Linq 4 | open MonoDevelop.Core 5 | open Mono.TextEditor 6 | open MonoDevelop.Projects.Text 7 | open MonoDevelop.Ide.Gui 8 | open MonoDevelop.Ide.Gui.Content 9 | open MonoDevelop.Ide.Editor 10 | 11 | type TestViewContent() = 12 | inherit ViewContent() 13 | let caretPositionSet = Event<_>() 14 | let textChanged = Event<_>() 15 | let name = FilePath() 16 | 17 | let data = MonoDevelop.Ide.Editor.TextEditorFactory.CreateNewEditor () 18 | 19 | member val Contents = ResizeArray([data :> obj]) with get, set 20 | member val Data = data 21 | 22 | override x.Load(fileName:FileOpenInformation) = null 23 | override x.Control = null 24 | 25 | override x.OnGetContents (t) = 26 | base.OnGetContents(t).Concat(x.Contents) 27 | 28 | //interface ITextEditorDataProvider with 29 | member x.GetTextEditorData() = data 30 | 31 | //interface IEditableTextBuffer with 32 | member x.HasInputFocus = false 33 | member x.LineCount = data.LineCount 34 | [] 35 | member x.CaretPositionSet = caretPositionSet.Publish 36 | [] 37 | member x.TextChanged = textChanged.Publish 38 | member x.SetCaretTo(line, column) =() 39 | member x.SetCaretTo(line, column, highlightCaretLine) =() 40 | member x.SetCaretTo(line, column, highlightCaretLine, centerCaret) =() 41 | member x.RunWhenLoaded(f) = f() 42 | member x.SelectedText with get() = "" and set (v:string) = () 43 | member x.CursorPosition with get() = data.CaretOffset and set v = data.CaretOffset <- v 44 | member x.SelectionStartPosition with get() = if data.IsSomethingSelected then data.SelectionRange.Offset else data.CaretOffset 45 | member x.SelectionEndPosition with get() = if data.IsSomethingSelected then data.SelectionRange.EndOffset else data.CaretOffset 46 | member x.Select(s, e) = 47 | if not (data.IsSomethingSelected) then data.CaretOffset 48 | else data.SelectionRange.EndOffset 49 | member x.ShowPosition(pos) = () 50 | 51 | member x.InsertText(pos, str:string) = 52 | data.InsertText(pos, str) 53 | str.Length 54 | member x.DeleteText(pos, length) = data.ReplaceText (pos, length, "") 55 | member x.EnableUndo = false 56 | member x.EnableRedo = false 57 | member x.Undo() = () 58 | member x.Redo() = () 59 | member x.OpenUndoGroup() = {new IDisposable with member x.Dispose() = ()} 60 | member x.Text with get() = data.Text and set v = data.Text <- v 61 | 62 | interface ITextFile with 63 | member x.Text with get() = data.Text 64 | member x.Name with get() = name 65 | member x.Length = data.Length 66 | member x.GetText(s, e) = data.GetTextBetween (s, e) 67 | member x.GetCharAt(pos) = data.GetCharAt(pos) 68 | member x.GetPositionFromLineColumn(line, column) = data.LocationToOffset (line, column) 69 | member x.GetLineColumnFromPosition(position, line, col) = 70 | let loc = data.OffsetToLocation (position) 71 | line <- loc.Line 72 | col <- loc.Column 73 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/TestWorkbenchWindow.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelopTests 2 | open System 3 | open Mono.Addins 4 | open MonoDevelop.Ide.Gui 5 | 6 | type TestWorkbenchWindow(viewContent) = 7 | 8 | let edc = DelegateEvent<_>() 9 | let closed = DelegateEvent<_>() 10 | let closing = DelegateEvent<_>() 11 | let avcc = DelegateEvent<_>() 12 | let viewsChanged = DelegateEvent<_>() 13 | 14 | interface IWorkbenchWindow with 15 | member x.SelectWindow () = () 16 | member x.SwitchView (viewNumber:int) = () 17 | member x.SwitchView (viewNumber:BaseViewContent) = () 18 | member x.FindView<'a>() = -1 19 | member val Title = "" with get,set 20 | member val Document = null with get, set 21 | member val DocumentType = "" with get, set 22 | member val ShowNotification = false with get, set 23 | member x.ViewContent with get() = viewContent 24 | member x.ActiveViewContent with get() = viewContent :> BaseViewContent and set v = () 25 | member x.ExtensionContext with get() = AddinManager.AddinEngine :> _ 26 | member x.CloseWindow (force) = true 27 | member x.AttachViewContent (subViewContent) = () 28 | member x.InsertViewContent(index, subViewContent) = () 29 | member x.SubViewContents with get() = Seq.empty 30 | member x.GetToolbar(targetView) = failwith "Not Implemented" 31 | 32 | [] 33 | member x.DocumentChanged = edc.Publish 34 | [] 35 | member x.Closed = closed.Publish 36 | [] 37 | member x.Closing = closing.Publish 38 | [] 39 | member x.ActiveViewContentChanged = avcc.Publish 40 | [] 41 | member x.ViewsChanged = viewsChanged.Publish 42 | -------------------------------------------------------------------------------- /MonoDevelop.FSharp.Tests/paket.references: -------------------------------------------------------------------------------- 1 | ExtCore 2 | FSharp.Compiler.Service 3 | FSharp.Core 4 | Mono.Cecil -------------------------------------------------------------------------------- /MonoDevelop.FSharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{165E4D13-19CC-4FCA-B4EC-F86DA08E6003}" 5 | ProjectSection(SolutionItems) = preProject 6 | paket.dependencies = paket.dependencies 7 | EndProjectSection 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.FSharp.Gui", "MonoDevelop.FSharp.Gui\MonoDevelop.FSharp.Gui.csproj", "{FD0D1033-9145-48E5-8ED8-E2365252878C}" 10 | EndProject 11 | Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "MonoDevelop.FSharp", "MonoDevelop.FSharpBinding\MonoDevelop.FSharp.fsproj", "{4C10F8F9-3816-4647-BA6E-85F5DE39883A}" 12 | EndProject 13 | Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "MonoDevelop.FSharp.Tests", "MonoDevelop.FSharp.Tests\MonoDevelop.FSharp.Tests.fsproj", "{A1A45375-7FB8-4F2A-850F-FBCC67739927}" 14 | EndProject 15 | Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "MonoDevelop.FSharpInteractive.Service", "MonoDevelop.FSharpi.Service\MonoDevelop.FSharpInteractive.Service.fsproj", "{20D6EC2C-B62E-49D1-B685-90D8967A5B5D}" 16 | EndProject 17 | Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "MonoDevelop.FSharp.Shared", "MonoDevelop.FSharp.Shared\MonoDevelop.FSharp.Shared.fsproj", "{AF5FEAD5-B50E-4F07-A274-32F23D5C504D}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {4C10F8F9-3816-4647-BA6E-85F5DE39883A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {4C10F8F9-3816-4647-BA6E-85F5DE39883A}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {4C10F8F9-3816-4647-BA6E-85F5DE39883A}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {4C10F8F9-3816-4647-BA6E-85F5DE39883A}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {A1A45375-7FB8-4F2A-850F-FBCC67739927}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {A1A45375-7FB8-4F2A-850F-FBCC67739927}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {A1A45375-7FB8-4F2A-850F-FBCC67739927}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {A1A45375-7FB8-4F2A-850F-FBCC67739927}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {FD0D1033-9145-48E5-8ED8-E2365252878C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {FD0D1033-9145-48E5-8ED8-E2365252878C}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {FD0D1033-9145-48E5-8ED8-E2365252878C}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {FD0D1033-9145-48E5-8ED8-E2365252878C}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {20D6EC2C-B62E-49D1-B685-90D8967A5B5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {20D6EC2C-B62E-49D1-B685-90D8967A5B5D}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {20D6EC2C-B62E-49D1-B685-90D8967A5B5D}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {20D6EC2C-B62E-49D1-B685-90D8967A5B5D}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {AF5FEAD5-B50E-4F07-A274-32F23D5C504D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {AF5FEAD5-B50E-4F07-A274-32F23D5C504D}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {AF5FEAD5-B50E-4F07-A274-32F23D5C504D}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {AF5FEAD5-B50E-4F07-A274-32F23D5C504D}.Release|Any CPU.Build.0 = Release|Any CPU 45 | EndGlobalSection 46 | GlobalSection(NestedProjects) = preSolution 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/CompilerService.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpBraceMatcher.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open System.Threading.Tasks 5 | open MonoDevelop 6 | open MonoDevelop.Core.Text 7 | open MonoDevelop.Ide.Editor 8 | open Microsoft.FSharp.Compiler 9 | open Microsoft.FSharp.Compiler.SourceCodeServices 10 | 11 | type FSharpBraceMatcher() = 12 | inherit AbstractBraceMatcher() 13 | let defaultMatcher = new DefaultBraceMatcher() 14 | 15 | override x.CanHandle editor = 16 | FileService.supportedFileName (editor.FileName.ToString()) 17 | 18 | override x.GetMatchingBracesAsync (editor, context, caretOffset, cancellationToken) = 19 | if caretOffset = -1 || caretOffset >= editor.Length then 20 | Task.FromResult(Nullable()) 21 | else 22 | let isFsi = editor.FileName.ToString() = "__FSI__.fsx" 23 | match editor.GetCharAt(caretOffset), isFsi with 24 | | '(', false 25 | | ')', false -> 26 | let computation = async { 27 | let getOffset (range:Range.range) = 28 | editor.LocationToOffset (range.StartLine, range.StartColumn+1) 29 | 30 | let projectFileName = 31 | if isNull context.Project then 32 | editor.FileName 33 | else 34 | context.Project.FileName 35 | 36 | let! braces = languageService.MatchingBraces(context.Name, projectFileName.ToString(), editor.Text) 37 | let matching = 38 | braces |> Seq.choose 39 | (fun (startRange, endRange) -> 40 | let startOffset = getOffset startRange 41 | let endOffset = getOffset endRange 42 | match (startOffset, endOffset) with 43 | | (startOffset, endOffset) when startOffset = caretOffset 44 | -> Some (startOffset, endOffset, true) 45 | | (startOffset, endOffset) when endOffset = caretOffset 46 | -> Some (startOffset, endOffset, false) 47 | | _ -> None) 48 | |> Seq.tryHead 49 | 50 | return 51 | match matching with 52 | | Some (startBrace, endBrace, isLeft) -> 53 | Nullable(new BraceMatchingResult(new TextSegment(startBrace, 1), new TextSegment(endBrace, 1), isLeft)) 54 | | None -> Nullable() 55 | 56 | } 57 | Async.StartAsTask (computation = computation, cancellationToken = cancellationToken) 58 | | _ -> defaultMatcher.GetMatchingBracesAsync (editor, context, caretOffset, cancellationToken) 59 | 60 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpDebuggerExpressionResolver.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | open MonoDevelop 3 | open MonoDevelop.Ide.Editor.Extension 4 | open MonoDevelop.Debugger 5 | 6 | type FSharpDebuggerExpressionResolver() = 7 | inherit TextEditorExtension() 8 | 9 | interface IDebuggerExpressionResolver with 10 | member x.ResolveExpressionAsync (doc, context, offset, cancellationToken) = 11 | let computation = async { 12 | let ast = context.TryGetAst() 13 | let location = 14 | match ast with 15 | | None -> None 16 | | Some pcr -> 17 | let location = doc.OffsetToLocation(offset) 18 | let line = doc.GetLine location.Line 19 | let lineTxt = doc.GetTextAt (line.Offset, line.Length) 20 | let symbol = pcr.GetSymbolAtLocation (location.Line, location.Column, lineTxt) |> Async.RunSynchronously 21 | match symbol with 22 | | Some symbolUse when not symbolUse.IsFromDefinition -> 23 | match symbolUse with 24 | | SymbolUse.ActivePatternCase apc -> 25 | Some (apc.DeclarationLocation, apc.DisplayName) 26 | | SymbolUse.Entity _ent -> None 27 | | SymbolUse.Field field -> 28 | Some (field.DeclarationLocation, field.DisplayName) 29 | | SymbolUse.GenericParameter gp -> 30 | Some (gp.DeclarationLocation, gp.DisplayName) 31 | //| CorePatterns.MemberFunctionOrValue 32 | | SymbolUse.Parameter p -> 33 | Some (p.DeclarationLocation, p.DisplayName) 34 | | SymbolUse.StaticParameter sp -> 35 | Some (sp.DeclarationLocation, sp.DisplayName) 36 | | SymbolUse.UnionCase _uc -> None 37 | | SymbolUse.Class _c -> None 38 | | SymbolUse.ClosureOrNestedFunction _cl -> None 39 | | SymbolUse.Constructor _ctor -> None 40 | | SymbolUse.Delegate _del -> None 41 | | SymbolUse.Enum enum -> 42 | Some (enum.DeclarationLocation, enum.DisplayName) 43 | | SymbolUse.Event _ev -> None 44 | | SymbolUse.Function _f -> None 45 | | SymbolUse.Interface _i -> None 46 | | SymbolUse.Module _m -> None 47 | | SymbolUse.Namespace _ns -> None 48 | | SymbolUse.Operator _op -> None 49 | | SymbolUse.Pattern _p -> None 50 | | SymbolUse.Property _pr -> 51 | let loc = symbolUse.RangeAlternate 52 | Some (loc, lineTxt.Substring(loc.StartColumn, loc.EndColumn-loc.StartColumn)) 53 | | SymbolUse.Record r -> 54 | let loc = r.DeclarationLocation 55 | Some (loc, r.DisplayName) 56 | | SymbolUse.TypeAbbreviation _ta -> None 57 | | SymbolUse.Union _un -> None 58 | | SymbolUse.Val v -> 59 | let loc = v.DeclarationLocation 60 | Some (loc, v.DisplayName) 61 | | SymbolUse.ValueType _vt -> None 62 | | _ -> None 63 | | _ -> None 64 | match location with 65 | | None -> return DebugDataTipInfo() 66 | | Some (range, name) -> 67 | let ts = Symbols.getTextSpan range doc 68 | return DebugDataTipInfo(ts, name)} 69 | 70 | Async.StartAsTask (computation, cancellationToken = cancellationToken) 71 | 72 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpFoldingParser.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | open System 3 | open MonoDevelop.Ide.TypeSystem 4 | 5 | /// The folding parser is used for generating a preliminary parsed document that does not 6 | /// contain a full dom - only some basic lexical constructs such as comments or pre processor directives. 7 | /// As we dont currently fold comments or compiler directives this is an empty DefaultParsedDocument 8 | type FSharpFoldingParser() = 9 | interface IFoldingParser with 10 | member x.Parse(fileName, _content) = 11 | DefaultParsedDocument (fileName) :> _ -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpFormattingPanelWidget.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open Gtk 5 | open MonoDevelop.Core 6 | open MonoDevelop.Ide 7 | open MonoDevelop.Components.PropertyGrid 8 | open Mono.Unix 9 | 10 | // Handwritten GUI, feel free to edit 11 | 12 | [] 13 | type FSharpFormattingPolicyPanelWidget() = 14 | inherit Gtk.Bin() 15 | 16 | let store = new ListStore (typedefof, typedefof) 17 | let mutable policy = FSharpFormattingPolicy() 18 | let mutable vbox2 : Gtk.VBox = null 19 | let mutable hbox1 : Gtk.HBox = null 20 | let mutable boxScopes : Gtk.VBox = null 21 | let mutable GtkScrolledWindow : Gtk.ScrolledWindow = null 22 | let mutable listView : Gtk.TreeView = null 23 | let mutable hbox2 : Gtk.HBox = null 24 | let mutable vbox4 : Gtk.VBox = null 25 | let mutable tableScopes : Gtk.Table = null 26 | let mutable propertyGrid : PropertyGrid = null 27 | 28 | let getName format = 29 | if format = policy.DefaultFormat then 30 | GettextCatalog.GetString ("Default") 31 | else 32 | let i = policy.Formats.IndexOf (format) + 1 33 | String.Format(GettextCatalog.GetString ("Format #{0}"), i) 34 | 35 | let updateCurrentName() = 36 | let it : TreeIter ref = ref Unchecked.defaultof<_> 37 | match listView.Selection.GetSelected(it) with 38 | | true -> 39 | let s = store.GetValue(!it, 1) :?> FSharpFormattingSettings 40 | store.SetValue (!it, 0, getName s) 41 | | false -> () 42 | 43 | let fillFormat so = 44 | match so with 45 | | Some format -> 46 | propertyGrid.CurrentObject <- format 47 | | None -> () 48 | updateCurrentName() 49 | propertyGrid.Sensitive <- so.IsSome 50 | 51 | let handleListViewSelectionChanged _ = 52 | let it : TreeIter ref = ref Unchecked.defaultof<_> 53 | match listView.Selection.GetSelected(it) with 54 | | true -> 55 | let format = store.GetValue(!it, 1) :?> FSharpFormattingSettings 56 | fillFormat(Some format) 57 | | _ -> 58 | fillFormat(None) 59 | 60 | let appendSettings format = 61 | store.AppendValues(getName format, format) |> ignore 62 | 63 | let update() = 64 | store.Clear() 65 | appendSettings(policy.DefaultFormat) 66 | for s in policy.Formats do 67 | appendSettings s 68 | 69 | member private this.Build() = 70 | Stetic.Gui.Initialize(this) 71 | // Widget MonoDevelop.Xml.Formatting.XmlFormattingPolicyPanelWidget 72 | Stetic.BinContainer.Attach (this) |> ignore 73 | this.Name <- "MonoDevelop.FSharp.FSharpFormattingPolicyPanelWidget" 74 | // Container child MonoDevelop.Xml.Formatting.XmlFormattingPolicyPanelWidget.Gtk.Container+ContainerChild 75 | vbox2 <- new Gtk.VBox() 76 | vbox2.Name <- "vbox2" 77 | vbox2.Spacing <- 6 78 | // Container child vbox2.Gtk.Box+BoxChild 79 | hbox1 <- new Gtk.HBox() 80 | hbox1.Name <- "hbox1" 81 | hbox1.Spacing <- 6 82 | // Container child hbox1.Gtk.Box+BoxChild 83 | boxScopes <- new Gtk.VBox() 84 | boxScopes.Name <- "boxScopes" 85 | boxScopes.Spacing <- 6 86 | // Container child boxScopes.Gtk.Box+BoxChild 87 | GtkScrolledWindow <- new Gtk.ScrolledWindow() 88 | GtkScrolledWindow.Name <- "GtkScrolledWindow" 89 | GtkScrolledWindow.ShadowType <- ShadowType.In 90 | // Container child GtkScrolledWindow.Gtk.Container+ContainerChild 91 | listView <- new Gtk.TreeView() 92 | listView.CanFocus <- true 93 | listView.Name <- "listView" 94 | listView.HeadersVisible <- false 95 | GtkScrolledWindow.Add(listView) 96 | boxScopes.Add(GtkScrolledWindow) 97 | let w2 = boxScopes.[GtkScrolledWindow] :?> Gtk.Box.BoxChild 98 | w2.Position <- 0 99 | // Container child boxScopes.Gtk.Box+BoxChild 100 | hbox2 <- new Gtk.HBox() 101 | hbox2.Name <- "hbox2" 102 | hbox2.Spacing <- 6 103 | boxScopes.Add(hbox2) 104 | let w5 = boxScopes.[hbox2] :?> Gtk.Box.BoxChild 105 | w5.Position <- 1 106 | w5.Expand <- false 107 | w5.Fill <- false 108 | hbox1.Add(boxScopes) 109 | let w6 = hbox1.[boxScopes] :?> Gtk.Box.BoxChild 110 | w6.Position <- 0 111 | w6.Expand <- false 112 | w6.Fill <- false 113 | 114 | // Container child hbox1.Gtk.Box+BoxChild 115 | vbox4 <- new Gtk.VBox() 116 | vbox4.Name <- "vbox4" 117 | vbox4.Spacing <- 6 118 | 119 | // Container child vbox4.Gtk.Box+BoxChild 120 | tableScopes <- new Gtk.Table(uint32 3, uint32 3, false) 121 | tableScopes.Name <- "tableScopes" 122 | tableScopes.RowSpacing <- uint32 6 123 | tableScopes.ColumnSpacing <- uint32 6 124 | vbox4.Add(tableScopes) 125 | let w8 = vbox4.[tableScopes] :?> Gtk.Box.BoxChild 126 | w8.Position <- 1 127 | w8.Expand <- false 128 | w8.Fill <- false 129 | // Container child vbox4.Gtk.Box+BoxChild 130 | propertyGrid <- new PropertyGrid() 131 | propertyGrid.Name <- "propertyGrid" 132 | propertyGrid.ShowToolbar <- false 133 | propertyGrid.ShowHelp <- false 134 | vbox4.Add (propertyGrid) 135 | let w9 = vbox4.[propertyGrid] :?> Gtk.Box.BoxChild 136 | w9.Position <- 2 137 | hbox1.Add(vbox4) 138 | let w10 = hbox1.[vbox4] :?> Gtk.Box.BoxChild 139 | w10.Position <- 1 140 | 141 | vbox2.Add(hbox1) 142 | let w11 = vbox2.[hbox1] :?> Gtk.Box.BoxChild 143 | w11.Position <- 0 144 | 145 | this.Add(vbox2) 146 | if this.Child <> null then 147 | this.Child.ShowAll() 148 | boxScopes.Hide() 149 | 150 | member this.Initialize() = 151 | this.Build() 152 | 153 | propertyGrid.ShowToolbar <- false 154 | propertyGrid.ShadowType <- ShadowType.In 155 | 156 | listView.Model <- store 157 | listView.Selection.Changed.Add(handleListViewSelectionChanged) 158 | 159 | member __.CommitPendingChanges() = 160 | propertyGrid.CommitPendingChanges() 161 | 162 | member __.SetFormat(p : FSharpFormattingPolicy) = 163 | policy <- p 164 | update() 165 | match store.GetIterFirst() with 166 | | true, it -> 167 | listView.Selection.SelectIter(it) 168 | | _ -> () -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpFormattingPolicy.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open System.Text 5 | open MonoDevelop.Ide.Gui.Content 6 | open MonoDevelop.Core 7 | open MonoDevelop.Core.Serialization 8 | open System.ComponentModel 9 | open MonoDevelop.Projects.Policies 10 | 11 | type FSharpFormattingSettings() = 12 | [] 13 | [] 14 | [] 15 | member val IndentOnTryWith = false with get, set 16 | 17 | [] 18 | [] 19 | [] 20 | member val ReorderOpenDeclaration = false with get, set 21 | 22 | [] 23 | [] 24 | [] 25 | member val SpaceAfterComma = true with get, set 26 | 27 | [] 28 | [] 29 | [] 30 | member val SpaceAfterSemicolon = true with get, set 31 | 32 | [] 33 | [] 34 | [] 35 | member val SpaceAroundDelimiter = true with get, set 36 | 37 | [] 38 | [] 39 | [] 40 | member val SpaceBeforeArgument = true with get, set 41 | 42 | [] 43 | [] 44 | [] 45 | member val SpaceBeforeColon = true with get, set 46 | 47 | // [] 48 | // [] 49 | // [] 50 | // member val SemicolonAtEndOfLine = false with get, set 51 | 52 | member x.Clone() = 53 | x.MemberwiseClone() :?> FSharpFormattingSettings 54 | 55 | [] 56 | [] 57 | type FSharpFormattingPolicy() = 58 | [] 59 | member val Formats = ResizeArray() with get, set 60 | 61 | [] 62 | member val DefaultFormat = FSharpFormattingSettings() with get, set 63 | 64 | member x.Clone() = 65 | let clone = FSharpFormattingPolicy() 66 | clone.DefaultFormat <- x.DefaultFormat.Clone() 67 | for f in x.Formats do 68 | clone.Formats.Add (f.Clone()) 69 | clone 70 | 71 | interface IEquatable with 72 | member this.Equals(other) = 73 | this.DefaultFormat = other.DefaultFormat 74 | && Seq.forall (fun f -> Seq.exists (fun f' -> f' = f) other.Formats) this.Formats 75 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpFormattingPolicy.xml: -------------------------------------------------------------------------------- 1 |  2 | 11 | 12 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpFormattingPolicyPanel.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open Gtk 4 | open MonoDevelop.Components 5 | open MonoDevelop.Ide.Gui.Dialogs 6 | 7 | type FSharpFormattingPolicyPanel() = 8 | inherit MimeTypePolicyOptionsPanel() 9 | let mutable policy = FSharpFormattingPolicy() 10 | let mutable panel = new FSharpFormattingPolicyPanelWidget() 11 | override __.CreatePanelWidget() = 12 | panel <- new FSharpFormattingPolicyPanelWidget() 13 | panel.Initialize() 14 | Control.op_Implicit panel 15 | 16 | override __.LoadFrom(p : FSharpFormattingPolicy) = 17 | policy <- p.Clone() 18 | panel.SetFormat(policy) 19 | 20 | override __.GetPolicy() = 21 | panel.CommitPendingChanges () 22 | policy 23 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpHighlightUsagesExtension.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open System.Threading.Tasks 5 | open Mono.TextEditor 6 | open MonoDevelop 7 | open MonoDevelop.Core 8 | open MonoDevelop.Ide 9 | open MonoDevelop.Ide.FindInFiles 10 | open MonoDevelop.Ide.Editor.Extension 11 | open MonoDevelop.Projects 12 | open ICSharpCode.NRefactory.Semantics 13 | open ICSharpCode.NRefactory.TypeSystem 14 | open ICSharpCode.NRefactory.TypeSystem.Implementation 15 | open Microsoft.FSharp.Compiler.SourceCodeServices 16 | 17 | /// MD/XS extension for highlighting the usages of a symbol within the current buffer. 18 | type HighlightUsagesExtension() = 19 | inherit AbstractUsagesExtension<(string * FSharpSymbolUse []) option>() 20 | 21 | override x.Initialize() = 22 | base.Initialize () 23 | let syntaxMode = new FSharpSyntaxMode (x.Editor, x.DocumentContext) 24 | x.Editor.SemanticHighlighting <- syntaxMode 25 | 26 | override x.ResolveAsync (token) = 27 | match IdeApp.Workbench.ActiveDocument with 28 | | null -> Task.FromResult(None) 29 | | doc when doc.FileName = FilePath.Null || doc.FileName <> x.Editor.FileName || x.DocumentContext.ParsedDocument = null -> Task.FromResult(None) 30 | | _doc -> 31 | LoggingService.LogDebug("HighlightUsagesExtension: ResolveAsync starting on {0}", x.DocumentContext.Name |> IO.Path.GetFileName ) 32 | Async.StartAsTask ( 33 | cancellationToken = token, 34 | computation = async { 35 | try 36 | let line, col, lineStr = x.Editor.GetLineInfoByCaretOffset () 37 | let currentFile = x.DocumentContext.Name 38 | let source = x.Editor.Text 39 | let projectFile = x.DocumentContext.Project |> function null -> currentFile | project -> project.FileName.ToString() 40 | let! symbolReferences = languageService.GetUsesOfSymbolAtLocationInFile (projectFile, currentFile, 0, source, line, col, lineStr) 41 | return symbolReferences 42 | with 43 | | :? TaskCanceledException -> return None 44 | | exn -> LoggingService.LogError("Unhandled Exception in F# HighlightingUsagesExtension", exn) 45 | return None }) 46 | 47 | override x.GetReferencesAsync(resolveResult, token) = 48 | let references = 49 | if token.IsCancellationRequested then Seq.empty else 50 | 51 | try 52 | match resolveResult with 53 | | Some(fsSymbolName, references) -> 54 | LoggingService.LogDebug("HighlightUsagesExtension: GetReferences starting on {0}", x.DocumentContext.Name |> IO.Path.GetFileName) 55 | //TODO: Can we use the DisplayName from the symbol rather than the last element in ident islands? 56 | // If we could then we could remove the Parsing.findLongIdents in GetUsesOfSymbolAtLocationInFile. 57 | references 58 | |> Seq.map (fun symbolUse -> NRefactory.createMemberReference(x.Editor, symbolUse, fsSymbolName)) 59 | | _ -> Seq.empty 60 | 61 | with 62 | | :? TaskCanceledException -> Seq.empty 63 | | exn -> LoggingService.LogError("Unhandled Exception in F# HighlightingUsagesExtension", exn) 64 | Seq.empty 65 | 66 | Task.FromResult references 67 | 68 | override x.Dispose () = 69 | x.Editor.SemanticHighlighting.Dispose() 70 | x.Editor.SemanticHighlighting <- null 71 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpIndentationTracker.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open MonoDevelop.Core 5 | open MonoDevelop.Ide.Editor 6 | open MonoDevelop.Ide.Editor.Extension 7 | 8 | type FSharpTextPasteHandler(editor:TextEditor) = 9 | inherit TextPasteHandler() 10 | override x.GetCopyData(offset, _length) = 11 | // get the indent level the line was originally at 12 | let line = editor.OffsetToLineNumber offset 13 | let indent = editor.GetLineIndent line 14 | [|byte indent.Length|] 15 | 16 | override x.PostFomatPastedText (_offset, _length) = () 17 | 18 | 19 | override x.FormatPlainText(offset, text, copyData) = 20 | if editor.Options.IndentStyle = IndentStyle.Smart || 21 | editor.Options.IndentStyle = IndentStyle.Virtual then 22 | // adjust the original indentation size 23 | // for the new location 24 | let location = editor.OffsetToLocation offset 25 | if location.Column > 1 then 26 | let getIndent (line:string) = 27 | line.Length - (String.trimStart [|' '|] line).Length 28 | 29 | let fixIndent (line:string, indentDifference:int) = 30 | if indentDifference > 0 then 31 | (String(' ', indentDifference)) + line 32 | else 33 | line.Substring -indentDifference 34 | 35 | let line = location.Line 36 | 37 | let insertionIndent = editor.GetLineIndent line 38 | let lines = String.getLines text 39 | let firstLine = lines.[0] 40 | let firstLineIndent = if copyData.Length > 0 then 41 | int copyData.[0] 42 | else 43 | getIndent firstLine 44 | 45 | let indentDifference = insertionIndent.Length - firstLineIndent 46 | let remainingLines = lines |> Seq.skip (1) 47 | |> Seq.map(fun line -> fixIndent(line, indentDifference)) 48 | let lines = remainingLines 49 | |> Seq.append (seq [(String.trimStart [|' '|] firstLine)]) 50 | let res = String.Join (editor.Options.DefaultEolMarker, lines) 51 | 52 | res 53 | else 54 | text 55 | else 56 | text 57 | 58 | type FSharpIndentationTracker(editor:TextEditor) = 59 | inherit IndentationTracker () 60 | let indentSize = editor.Options.IndentationSize 61 | do 62 | editor.SetTextPasteHandler (FSharpTextPasteHandler(editor)) 63 | 64 | // Lines ending in these strings will be indented 65 | let indenters = ["=";" do"; "("; "{";"[";"[|";"->";" try"; " then"; " else"; "("] 66 | 67 | let (|AddIndent|_|) (x:string) = 68 | if indenters |> List.exists(x.EndsWith) then Some () 69 | else None 70 | let (|Match|_|) (x:string) = 71 | if x.EndsWith "with" && x.Contains("match ") then Some (x.LastIndexOf "match ") 72 | else None 73 | 74 | let initialWhiteSpace (s:string) offset = 75 | if offset >= s.Length then 0 else 76 | let s = s.Substring offset 77 | s.Length - s.TrimStart([|' '|]).Length 78 | 79 | let rec getIndentation lineDistance (line: IDocumentLine) = 80 | if line = null then "" else 81 | 82 | match editor.GetLineText(line.LineNumber).TrimEnd() with 83 | | x when String.IsNullOrWhiteSpace(x) -> getIndentation (lineDistance + 1) line.PreviousLine 84 | | Match i when lineDistance < 2 -> String(' ', i) 85 | | AddIndent when lineDistance < 2 -> String(' ', line.GetIndentation(editor).Length + indentSize) 86 | | _ -> line.GetIndentation editor 87 | 88 | let getIndentString lineNumber = 89 | let caretColumn = editor.CaretColumn 90 | let line = editor.GetLine lineNumber 91 | 92 | let indentation = getIndentation 0 line 93 | if line = null then indentation else 94 | // Find white space in front of the caret and strip it out 95 | let text = editor.GetLineText(line.LineNumber) 96 | //TODO using 0 instead of column, which we dont have now 97 | let reIndent = 0 = text.Length + 1 && caretColumn = 1 98 | if not reIndent then indentation else 99 | let indent = getIndentation 0 (line.PreviousLine) 100 | let initialWs = initialWhiteSpace text 0 101 | if initialWs >= indent.Length then indentation else 102 | indent.Substring(initialWhiteSpace text 0) 103 | 104 | override x.GetIndentationString (lineNumber) = 105 | try 106 | let line = editor.GetLine (lineNumber) 107 | let indent = 108 | if line = null then "" else 109 | getIndentString lineNumber 110 | LoggingService.LogDebug ("FSharpIndentationTracker: indent: '{0}'", indent) 111 | indent 112 | with 113 | | ex -> LoggingService.LogError ("FSharpIndentationTracker", ex) 114 | "" 115 | 116 | override x.SupportedFeatures = IndentatitonTrackerFeatures.None 117 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpNavigationTextEditorExtension.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System.Threading.Tasks 4 | open MonoDevelop 5 | open MonoDevelop.Core 6 | open MonoDevelop.Ide 7 | open MonoDevelop.Ide.Editor 8 | open MonoDevelop.Ide.Editor.Extension 9 | open Microsoft.FSharp.Compiler 10 | open Microsoft.FSharp.Compiler.SourceCodeServices 11 | open ExtCore.Control 12 | 13 | type FSharpNavigationTextEditorExtension() = 14 | inherit AbstractNavigationExtension() 15 | 16 | override x.RequestLinksAsync(offset, _length, token) = 17 | // return all links for the line at offset 18 | let editor = base.Editor 19 | let documentContext = base.DocumentContext 20 | 21 | let computation = async { 22 | if documentContext :? FsiDocumentContext then return Seq.empty 23 | else 24 | match documentContext.ParsedDocument |> Option.tryCast with 25 | | Some doc -> 26 | match doc.TryGetAst () with 27 | | None -> return Seq.empty 28 | | Some _ast -> 29 | let getOffset(pos: Range.pos) = 30 | editor.LocationToOffset (DocumentLocation(pos.Line, pos.Column + 1)) 31 | 32 | let line = editor.OffsetToLineNumber offset 33 | 34 | let segmentFromSymbol (symbol: FSharpSymbolUse) = 35 | let range = symbol.RangeAlternate 36 | let startOffset = getOffset range.Start 37 | let endOffset = getOffset range.End 38 | let text = editor.GetTextBetween(startOffset, endOffset) 39 | let lastDot = text.LastIndexOf "." 40 | let correctedOffset = 41 | if lastDot <> -1 then 42 | startOffset + lastDot + 1 43 | else 44 | startOffset 45 | 46 | AbstractNavigationExtension.NavigationSegment(correctedOffset, endOffset - correctedOffset, 47 | (fun () -> GLib.Timeout.Add (50u, fun () -> Refactoring.jumpToDeclaration(editor, documentContext, symbol) 48 | false) |> ignore)) 49 | let filterSymbols (symbol: FSharpSymbolUse) = 50 | symbol.RangeAlternate.StartLine = line 51 | 52 | && Refactoring.Operations.canJump symbol editor.FileName documentContext.Project.ParentSolution 53 | 54 | return doc.AllSymbolsKeyed.Values 55 | |> Seq.filter filterSymbols 56 | |> Seq.map segmentFromSymbol 57 | 58 | | None -> return Seq.empty 59 | } 60 | 61 | Async.StartAsTask(computation, cancellationToken = token) 62 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpOutlineTextEditorExtension.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open ExtCore.Control 5 | open Gtk 6 | open MonoDevelop 7 | open MonoDevelop.Components 8 | open MonoDevelop.Core 9 | open MonoDevelop.DesignerSupport 10 | open MonoDevelop.Ide.Editor.Extension 11 | open MonoDevelop.Ide.Gui.Components 12 | open MonoDevelop.Ide 13 | open MonoDevelop.Projects 14 | open Microsoft.FSharp.Compiler.SourceCodeServices 15 | 16 | type FSharpOutlineTextEditorExtension() as x = 17 | inherit TextEditorExtension() 18 | let mutable treeView : PadTreeView option = None 19 | let mutable refreshingOutline : bool = false 20 | let mutable timerId : uint32 = 0u 21 | let mutable handler : IDisposable = null 22 | 23 | let refillTree() = 24 | match treeView with 25 | | Some(treeView) -> 26 | 27 | Runtime.AssertMainThread() 28 | refreshingOutline <- false 29 | 30 | if treeView.IsRealized then 31 | x.DocumentContext.TryGetAst() |> Option.iter (fun ast -> 32 | let treeStore = treeView.Model :?> TreeStore 33 | treeStore.Clear() 34 | let toplevel = ast.GetNavigationItems() 35 | |> Array.sortBy(fun xs -> xs.Declaration.Range.StartLine) 36 | 37 | for item in toplevel do 38 | let iter = treeStore.AppendValues(item.Declaration) 39 | let children = item.Nested 40 | |> Array.sortBy(fun xs -> xs.Range.StartLine) 41 | 42 | for nested in children do 43 | treeStore.AppendValues(iter, [| nested |]) |> ignore 44 | 45 | treeView.ExpandAll()) 46 | Gdk.Threads.Leave() 47 | timerId <- 0u 48 | | None -> () 49 | 50 | refreshingOutline <- false 51 | false 52 | 53 | member private x.updateDocumentOutline _ = 54 | if not refreshingOutline then 55 | refreshingOutline <- true 56 | timerId <- GLib.Timeout.Add (1000u, (fun _ -> refillTree())) 57 | 58 | override x.Initialize() = 59 | base.Initialize() 60 | handler <- x.DocumentContext.DocumentParsed.Subscribe(fun o e -> x.updateDocumentOutline()) 61 | 62 | override x.Dispose() = 63 | handler.Dispose() 64 | if timerId > 0u then 65 | GLib.Source.Remove timerId |> ignore 66 | timerId <- 0u 67 | base.Dispose() 68 | 69 | override x.IsValidInContext context = 70 | LanguageBindingService.GetBindingPerFileName (context.Name) <> null; 71 | 72 | interface IOutlinedDocument with 73 | member x.GetOutlineWidget() = 74 | match treeView with 75 | | Some(treeView) -> treeView :> Widget 76 | | None -> 77 | let treeStore = new TreeStore(typedefof) 78 | let padTreeView = new PadTreeView(treeStore, HeadersVisible = true) 79 | 80 | let setCellIcon _column (cellRenderer : CellRenderer) (treeModel : TreeModel) (iter : TreeIter) = 81 | let pixRenderer = cellRenderer :?> CellRendererImage 82 | let item = treeModel.GetValue(iter, 0) :?> FSharpNavigationDeclarationItem 83 | pixRenderer.Image <- ImageService.GetIcon(ServiceUtils.getIcon item, Gtk.IconSize.Menu) 84 | 85 | let setCellText _column (cellRenderer : CellRenderer) (treeModel : TreeModel) (iter : TreeIter) = 86 | let renderer = cellRenderer :?> CellRendererText 87 | let item = treeModel.GetValue(iter, 0) :?> FSharpNavigationDeclarationItem 88 | renderer.Text <- item.Name 89 | let jumpToDeclaration focus = 90 | let iter : TreeIter ref = ref Unchecked.defaultof<_> 91 | if padTreeView.Selection.GetSelected(iter) then 92 | let node = padTreeView.Model.GetValue(!iter, 0) :?> FSharpNavigationDeclarationItem 93 | let (scol,sline) = node.Range.StartColumn, node.Range.StartLine 94 | IdeApp.Workbench.OpenDocument (x.Editor.FileName, null, max 1 sline, max 1 scol) |> ignore 95 | if focus then 96 | x.Editor.GrabFocus() 97 | 98 | treeView <- Some padTreeView 99 | 100 | let pixRenderer = new CellRendererImage(Xpad = 0u, Ypad = 0u) 101 | padTreeView.TextRenderer.Xpad <- 0u 102 | padTreeView.TextRenderer.Ypad <- 0u 103 | 104 | let treeCol = new TreeViewColumn() 105 | treeCol.PackStart(pixRenderer, false) 106 | treeCol.SetCellDataFunc(pixRenderer, new TreeCellDataFunc(setCellIcon)) 107 | treeCol.PackStart(padTreeView.TextRenderer, true) 108 | treeCol.SetCellDataFunc(padTreeView.TextRenderer, new TreeCellDataFunc(setCellText)) 109 | 110 | padTreeView.AppendColumn treeCol |> ignore 111 | padTreeView.Realized.Add(fun _ -> refillTree |> ignore) 112 | padTreeView.Selection.Changed.Subscribe(fun _ -> jumpToDeclaration false) |> ignore 113 | padTreeView.RowActivated.Subscribe(fun _ -> jumpToDeclaration true) |> ignore 114 | 115 | let sw = new CompactScrolledWindow() 116 | sw.Add padTreeView 117 | sw.ShowAll() 118 | sw :> Widget 119 | 120 | member x.GetToolbarWidgets() = [] :> _ 121 | 122 | member x.ReleaseOutlineWidget() = 123 | treeView |> Option.iter(fun tv -> Option.tryCast(tv.Parent) 124 | |> Option.iter (fun sw -> sw.Destroy()) 125 | 126 | match tv.Model with 127 | :? TreeStore as ts -> ts.Dispose() 128 | | _ -> ()) 129 | treeView <- None 130 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpParsedDocument.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open ICSharpCode.NRefactory.TypeSystem 4 | open Microsoft.FSharp.Compiler 5 | open MonoDevelop.Core 6 | open MonoDevelop.Ide 7 | open MonoDevelop.Ide.Editor 8 | open MonoDevelop.Ide.TypeSystem 9 | open System 10 | open System.Collections.Generic 11 | open System.IO 12 | open System.Threading 13 | open MonoDevelop 14 | open Microsoft.FSharp.Compiler.SourceCodeServices 15 | 16 | 17 | type FSharpParsedDocument(fileName, location: DocumentLocation option) = 18 | inherit DefaultParsedDocument(fileName,Flags = ParsedDocumentFlags.NonSerializable) 19 | member val Tokens : (FSharpTokenInfo list * int64) list option = None with get,set 20 | member val AllSymbolsKeyed = Dictionary() :> IDictionary<_,_> with get, set 21 | member x.ParsedLocation = location 22 | 23 | [] 24 | module DocumentContextExt = 25 | type DocumentContext with 26 | member x.GetWorkingFolder() = 27 | if IdeApp.Workbench.ActiveDocument <> null && FileService.isInsideFSharpFile() then 28 | let doc = IdeApp.Workbench.ActiveDocument.FileName.ToString() 29 | if doc <> null then Path.GetDirectoryName(doc) |> Some else None 30 | else None 31 | 32 | member x.TryGetFSharpParsedDocument() = 33 | x.TryGetParsedDocument() 34 | |> Option.bind (function :? FSharpParsedDocument as fpd -> Some fpd | _ -> None) -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpResolverProvider.fs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------- 2 | // Resolves locations to NRefactory Symbols and is used for Highlight usages and goto declaration 3 | // -------------------------------------------------------------------------------------- 4 | 5 | namespace MonoDevelop.FSharp 6 | 7 | open System 8 | open MonoDevelop 9 | open MonoDevelop.Core 10 | open MonoDevelop.Ide 11 | open MonoDevelop.Ide.Gui 12 | open MonoDevelop.Ide.Editor 13 | open MonoDevelop.Ide.Gui.Content 14 | open ICSharpCode.NRefactory 15 | open Microsoft.FSharp.Compiler.SourceCodeServices 16 | open ExtCore.Control 17 | 18 | /// Resolves locations to NRefactory symbols and ResolveResult objects. 19 | type FSharpResolverProvider() = 20 | 21 | interface ITextEditorResolverProvider with 22 | /// Get tool-tip at the specified offset (from the start of the file) 23 | member x.GetLanguageItem(doc:Document, offset:int, region:DocumentRegion byref): Microsoft.CodeAnalysis.ISymbol = 24 | 25 | try 26 | if doc.Editor = null then null else 27 | let docText = doc.Editor.Text 28 | if docText = null || offset >= docText.Length || offset < 0 then null else 29 | let filename =doc.FileName.FullPath.ToString() 30 | LoggingService.LogDebug "ResolverProvider: Getting results of type checking" 31 | // Try to get typed result - with the specified timeout 32 | let curVersion = doc.Editor.Version 33 | let isObsolete = 34 | IsResultObsolete(fun () -> 35 | let doc = IdeApp.Workbench.GetDocument(filename) 36 | let newVersion = doc.Editor.Version 37 | if newVersion.BelongsToSameDocumentAs(curVersion) && newVersion.CompareAge(curVersion) = 0 38 | then 39 | false 40 | else 41 | LoggingService.LogDebug ("FSharpResolverProvider: type check of {0} is obsolete, cancelled", IO.Path.GetFileName filename) 42 | true ) 43 | 44 | let results = 45 | asyncMaybe { 46 | let projectFile = doc.Project |> function null -> filename | project -> project.FileName.ToString() 47 | let! tyRes = languageService.GetTypedParseResultWithTimeout (projectFile, filename, 0, docText, AllowStaleResults.MatchingSource, obsoleteCheck=isObsolete) 48 | LoggingService.LogDebug "ResolverProvider: Getting declaration location" 49 | // Get the declaration location from the language service 50 | let line, col, lineStr = doc.Editor.GetLineInfoFromOffset offset 51 | let! fsSymbolUse = tyRes.GetSymbolAtLocation(line, col, lineStr) 52 | let! findDeclarationResult = tyRes.GetDeclarationLocation(line, col, lineStr) |> Async.map Some 53 | let domRegion = 54 | match findDeclarationResult with 55 | | FSharpFindDeclResult.DeclFound(m) -> 56 | LoggingService.LogDebug("ResolverProvider: found, line = {0}, col = {1}, file = {2}", m.StartLine, m.StartColumn, m.FileName) 57 | DocumentRegion(m.StartLine, m.EndLine, m.StartColumn+1, m.EndColumn+1) 58 | | FSharpFindDeclResult.DeclNotFound(notfound) -> 59 | match notfound with 60 | | FSharpFindDeclFailureReason.Unknown -> LoggingService.LogWarning "Declaration not found: Unknown" 61 | | FSharpFindDeclFailureReason.NoSourceCode -> LoggingService.LogWarning "Declaration not found: No Source Code" 62 | | FSharpFindDeclFailureReason.ProvidedType(t) -> LoggingService.LogWarning("Declaration not found: ProvidedType {0}", t) 63 | | FSharpFindDeclFailureReason.ProvidedMember(m) -> LoggingService.LogWarning("Declaration not found: ProvidedMember {0}", m) 64 | DocumentRegion () 65 | 66 | // This is the NRefactory symbol for the item - the Region is used for goto-definition 67 | let lastIdent = Symbols.lastIdent col lineStr 68 | 69 | return fsSymbolUse, lastIdent, domRegion } 70 | match Async.RunSynchronously (results, ServiceSettings.blockingTimeout) with 71 | | Some (symbolUse, lastIdent, dom) -> 72 | region <- dom 73 | 74 | let roslynLocs = 75 | Symbols.getTrimmedTextSpanForDeclarations lastIdent symbolUse 76 | |> Seq.map (fun (fileName, ts, ls) -> Microsoft.CodeAnalysis.Location.Create(fileName, ts, ls)) 77 | |> System.Collections.Immutable.ImmutableArray.ToImmutableArray 78 | let roslynSymbol = Roslyn.FsharpSymbol (symbolUse, roslynLocs) 79 | roslynSymbol :> _ 80 | | _ -> null 81 | 82 | with exn -> 83 | LoggingService.LogError("ResolverProvider: Exception while retrieving resolve result", exn) 84 | null 85 | 86 | member x.GetLanguageItem(doc:Document, offset:int, _identifier:string): Microsoft.CodeAnalysis.ISymbol = 87 | LoggingService.LogDebug "ResolverProvider: GetLanguageItem" 88 | let (result, _region) = (x :> ITextEditorResolverProvider).GetLanguageItem(doc, offset) 89 | result 90 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpStylePolicy.xml: -------------------------------------------------------------------------------- 1 |  2 | 120 3 | 4 4 | True 5 | True 6 | True 7 | Native 8 | 9 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpTokens.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | open System 3 | open Microsoft.FSharp.Compiler.SourceCodeServices 4 | open MonoDevelop 5 | open MonoDevelop.Ide.Editor 6 | open ExtCore.Control 7 | open MonoDevelop.Core 8 | open System.IO 9 | 10 | module Tokens = 11 | let getTokenAtPoint (editor:TextEditor) (context:DocumentContext) offset = 12 | let line, col, txt = editor.GetLineInfoFromOffset offset 13 | let getTokens() = 14 | Lexer.tokenizeLine txt [||] line txt Lexer.singleLineQueryLexState 15 | 16 | let lineTokens = 17 | maybe { let! pd = context.TryGetFSharpParsedDocument() 18 | let! tokens = pd.Tokens 19 | let lineTokens, _state = tokens |> List.item (line - 1) 20 | return lineTokens } 21 | |> Option.getOrElse getTokens 22 | 23 | let caretToken = lineTokens |> Lexer.findTokenAt col 24 | match caretToken with 25 | | Some token -> Some token 26 | | None -> // the background semantic parse hasn't caught up yet, 27 | // so tokenize the current line now 28 | getTokens() |> Lexer.findTokenAt col 29 | 30 | let isInvalidTipTokenAtPoint (editor:TextEditor) (context:DocumentContext) offset = 31 | match getTokenAtPoint editor context offset with 32 | | Some token -> Lexer.isNonTipToken token 33 | | None -> true 34 | 35 | let isInvalidCompletionToken (token:FSharpTokenInfo option) = 36 | match token with 37 | | Some token -> Lexer.isNonTipToken token 38 | | None -> false 39 | 40 | let tryGetTokens source defines fileName = 41 | try 42 | LoggingService.LogDebug ("FSharpParser: Processing tokens for {0}", Path.GetFileName fileName) 43 | let readOnlyDoc = TextEditorFactory.CreateNewReadonlyDocument (source, fileName) 44 | let lines = readOnlyDoc.GetLines() |> Seq.map readOnlyDoc.GetLineText 45 | let tokens = Lexer.getTokensWithInitialState 0L lines fileName defines 46 | Some(tokens) 47 | with ex -> 48 | LoggingService.LogWarning ("FSharpParser: Couldn't update token information for {0}", Path.GetFileName fileName, ex) 49 | None -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FSharpTooltipProvider.fs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------- 2 | // Provides tool tips with F# hints for MonoDevelop 3 | // (this file implements MonoDevelop interfaces and calls 'LanguageService') 4 | // -------------------------------------------------------------------------------------- 5 | namespace MonoDevelop.FSharp 6 | 7 | open System 8 | open System.Threading.Tasks 9 | open MonoDevelop 10 | open MonoDevelop.Core 11 | open MonoDevelop.Components 12 | open MonoDevelop.Ide 13 | open MonoDevelop.Ide.CodeCompletion 14 | open MonoDevelop.Ide.Editor 15 | open Microsoft.FSharp.Compiler.SourceCodeServices 16 | open ExtCore.Control 17 | 18 | module TooltipImpl = 19 | let extraKeywords = ["let!";"do!";"return!";"use!";"yield!";"->";"<-";"<@";"@>";"<@@";"@@>";":>";":?>"] 20 | let tryKeyword col lineStr = 21 | maybe {let! (_col, keyword) = Parsing.findIdents col lineStr SymbolLookupKind.Simple 22 | let! keyword = keyword |> List.tryHead 23 | if PrettyNaming.KeywordNames |> List.contains keyword || extraKeywords |> List.contains keyword 24 | then return keyword 25 | else return! None } 26 | 27 | module MDTooltip = 28 | let keywordToTooltip (editor:TextEditor) line col (keyword:string) = 29 | let startOffset = editor.LocationToOffset(line, col - keyword.Length+1) 30 | let endOffset = startOffset + keyword.Length 31 | let segment = Text.TextSegment.FromBounds(startOffset, endOffset) 32 | let tip = SymbolTooltips.getKeywordTooltip keyword 33 | TooltipItem( tip, segment :> Text.ISegment) 34 | 35 | /// Resolves locations to tooltip items, and orchestrates their display. 36 | type FSharpTooltipProvider() = 37 | inherit TooltipProvider() 38 | 39 | //keep the last enterNotofy handler so we can remove the handler as a new TipWindow is created 40 | let mutable enterNotify = None : IDisposable option 41 | let killTooltipWindow() = enterNotify |> Option.iter (fun en -> en.Dispose ()) 42 | let noTooltip = Task.FromResult null 43 | 44 | override x.GetItem (editor, context, offset, cancellationToken) = 45 | try 46 | let doc = IdeApp.Workbench.ActiveDocument 47 | if doc = null then noTooltip else 48 | 49 | let file = doc.FileName.FullPath.ToString() 50 | 51 | if not (FileService.supportedFileName file) then noTooltip else 52 | 53 | let source = editor.Text 54 | if source = null || offset >= source.Length || offset < 0 then noTooltip else 55 | 56 | let line, col, lineStr = editor.GetLineInfoFromOffset offset 57 | 58 | if Tokens.isInvalidTipTokenAtPoint editor context offset then noTooltip else 59 | 60 | let tooltipComputation = 61 | asyncChoice { 62 | try 63 | LoggingService.LogDebug "TooltipProvider: Getting tool tip" 64 | let projectFile = context.Project |> function null -> file | project -> project.FileName.ToString() 65 | let! parseAndCheckResults = 66 | languageService.GetTypedParseResultIfAvailable (projectFile, file, source, AllowStaleResults.MatchingSource) 67 | |> Choice.ofOptionWith "TooltipProvider: ParseAndCheckResults not found" 68 | let! symbol = parseAndCheckResults.GetSymbolAtLocation(line, col, lineStr) |> AsyncChoice.ofOptionWith "TooltipProvider: ParseAndCheckResults not found" 69 | let! signature, xmldoc, footer = 70 | SymbolTooltips.getTooltipFromSymbolUse symbol 71 | |> Choice.ofOptionWith (sprintf "TooltipProvider: TootipText not returned\n %s\n %s" lineStr (String.replicate col "-" + "^")) 72 | 73 | let highlightedTip = syntaxHighlight signature, xmldoc, footer 74 | 75 | //get the TextSegment the the symbols range occupies 76 | let textSeg = Symbols.getTextSegment editor symbol col lineStr 77 | 78 | let tooltipItem = TooltipItem(highlightedTip, textSeg) 79 | return tooltipItem 80 | 81 | with 82 | | :? TimeoutException -> return! AsyncChoice.error "TooltipProvider: timeout" 83 | | ex -> return! AsyncChoice.error (sprintf "TooltipProvider: Error: %A" ex)} 84 | 85 | match TooltipImpl.tryKeyword col lineStr with 86 | | Some t -> 87 | let keywordTip = MDTooltip.keywordToTooltip editor line col t 88 | Task.FromResult keywordTip 89 | | None -> 90 | 91 | Async.StartAsTask( 92 | async { 93 | 94 | let! tooltipResult = tooltipComputation 95 | match tooltipResult with 96 | | Success(tip) -> return tip 97 | | Operators.Error(warning) -> LoggingService.LogWarning warning 98 | return Unchecked.defaultof<_> }, cancellationToken = cancellationToken) 99 | 100 | with exn -> 101 | LoggingService.LogError ("TooltipProvider: Error retrieving tooltip", exn) 102 | Task.FromResult null 103 | 104 | override x.CreateTooltipWindow (_editor, _context, item, _offset, _modifierState) = 105 | let doc = IdeApp.Workbench.ActiveDocument 106 | if (doc = null) then null else 107 | let (signature, summary, footer) = unbox item.Item 108 | let result = new TooltipInformationWindow(ShowArrow = true) 109 | let toolTipInfo = new TooltipInformation(SignatureMarkup=signature, FooterMarkup=footer) 110 | let formattedSummary = SymbolTooltips.formatSummary summary 111 | if not (String.IsNullOrWhiteSpace formattedSummary) then 112 | toolTipInfo.SummaryMarkup <- formattedSummary 113 | result.AddOverload(toolTipInfo) 114 | result.RepositionWindow () 115 | Control.op_Implicit result 116 | 117 | interface IDisposable with 118 | member x.Dispose() = killTooltipWindow() 119 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/FakeSearchCategory.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open System.Diagnostics 5 | open System.IO 6 | open System.Text.RegularExpressions 7 | open System.Threading 8 | open System.Threading.Tasks 9 | open ExtCore 10 | open MonoDevelop.Core 11 | open MonoDevelop.Core.Text 12 | open MonoDevelop.Components 13 | open MonoDevelop.Components.MainToolbar 14 | open MonoDevelop.Ide 15 | open MonoDevelop.Projects 16 | 17 | type FakePad() = 18 | inherit MonoDevelop.Ide.Gui.PadContent() 19 | let view = new FSharpConsoleView() 20 | 21 | do view.InitialiseEvents() 22 | 23 | 24 | member x.Run (baseDirectory, task, buildScript) = 25 | let fsiProcess = 26 | let startInfo = 27 | new ProcessStartInfo 28 | (FileName = buildScript, UseShellExecute = false, Arguments = task, 29 | RedirectStandardError = true, CreateNoWindow = true, RedirectStandardOutput = true, 30 | RedirectStandardInput = true, StandardErrorEncoding = Text.Encoding.UTF8, 31 | StandardOutputEncoding = Text.Encoding.UTF8, 32 | WorkingDirectory = baseDirectory) 33 | view.WriteOutput(sprintf "FAKE task runner: Starting %s %s" buildScript task, false) 34 | view.Clear() 35 | 36 | try 37 | Process.Start(startInfo) 38 | with e -> 39 | LoggingService.LogDebug (sprintf "FAKE task runner %s" (e.ToString())) 40 | reraise() 41 | do 42 | Event.merge fsiProcess.OutputDataReceived fsiProcess.ErrorDataReceived 43 | |> Event.filter (fun de -> de.Data <> null) 44 | |> Event.add (fun de -> Runtime.RunInMainThread(fun _ -> view.WriteOutput (de.Data + "\n", false)) |> ignore) 45 | 46 | fsiProcess.EnableRaisingEvents <- true 47 | fsiProcess.BeginOutputReadLine() 48 | fsiProcess.BeginErrorReadLine() 49 | 50 | override x.Control = Control.op_Implicit view 51 | override x.Initialize(_container:MonoDevelop.Ide.Gui.IPadWindow) = 52 | x.UpdateColors() 53 | x.UpdateFont() 54 | 55 | member x.UpdateColors() = 56 | match view.Child with 57 | | :? Gtk.TextView as v -> 58 | let colourStyles = Mono.TextEditor.Highlighting.SyntaxModeService.GetColorStyle(MonoDevelop.Ide.IdeApp.Preferences.ColorScheme.Value) 59 | let shouldMatch = PropertyService.Get ("FSharpBinding.MatchWithThemePropName", true) 60 | let themeTextColour = colourStyles.PlainText.Foreground |> cairoToGdk 61 | let themeBackColour = colourStyles.PlainText.Background |> cairoToGdk 62 | 63 | if shouldMatch then 64 | v.ModifyText(Gtk.StateType.Normal, themeTextColour) 65 | v.ModifyBase(Gtk.StateType.Normal, themeBackColour) 66 | else 67 | let textColour = PropertyService.Get ("FSharpBinding.TextColorPropName", "#000000") |> ColorHelpers.strToColor 68 | let backColour = PropertyService.Get ("FSharpBinding.BaseColorPropName", "#FFFFFF") |> ColorHelpers.strToColor 69 | v.ModifyText(Gtk.StateType.Normal, textColour) 70 | v.ModifyBase(Gtk.StateType.Normal, backColour) 71 | | _ -> () 72 | 73 | member x.UpdateFont() = 74 | let fontName = MonoDevelop.Ide.Fonts.FontService.MonospaceFont.Family 75 | let fontName = PropertyService.Get ("FSharpBinding.FsiFontName", fontName) 76 | LoggingService.logDebug "FAKE task runner: Loading font '%s'" fontName 77 | 78 | let font = Pango.FontDescription.FromString(fontName) 79 | view.SetFont(font) 80 | 81 | type FakeSearchResult(solution: Solution, match', matchedString, rank, scriptPath) = 82 | inherit SearchResult(match', matchedString, rank) 83 | static let fakePad = new FakePad() 84 | 85 | let addPad() = 86 | IdeApp.Workbench.AddPad(fakePad, 87 | "MonoDevelop.FSharp.FakePad", 88 | "FAKE", 89 | "Center Bottom", 90 | IconId("md-command")) 91 | 92 | override x.SearchResultType = 93 | SearchResultType.Type 94 | 95 | override x.Description = 96 | sprintf "Runs the FAKE %s task in %s" matchedString solution.Name 97 | 98 | override x.PlainText = "FAKE " + matchedString 99 | 100 | override x.Icon = 101 | getImage "md-command" 102 | 103 | override x.CanActivate = true 104 | 105 | override x.Activate() = 106 | let pad = IdeApp.Workbench.FindPad(fakePad) |> Option.ofNull 107 | let pad = 108 | match pad with 109 | | Some pad -> Some pad 110 | | None -> addPad() |> Option.ofNull 111 | 112 | pad |> Option.iter (fun p -> 113 | p.BringToFront() 114 | let padContent = p.Content :?> FakePad 115 | padContent.Run (string solution.BaseDirectory, matchedString, scriptPath)) 116 | 117 | type FakeSearchCategory() = 118 | inherit SearchCategory("FAKE", sortOrder = SearchCategory.FirstCategory) 119 | 120 | override x.get_Tags() = [|"fake"|] 121 | 122 | override x.IsValidTag _tag = 123 | true 124 | 125 | override x.GetResults(searchCallback, pattern, token) = 126 | 127 | let addResult (solution: Solution, m: Match, rank, scriptPath) = 128 | if token.IsCancellationRequested then () 129 | else 130 | let sr = FakeSearchResult(solution, pattern.Pattern, m.Groups.[1].Value, rank, scriptPath) 131 | searchCallback.ReportResult sr 132 | 133 | Task.Run( 134 | (fun () -> 135 | let matcher = StringMatcher.GetMatcher (pattern.Pattern, false) 136 | async { 137 | for solution in IdeApp.Workspace.GetAllSolutions() do 138 | 139 | let launcherScript = if Platform.IsWindows then 140 | "build.cmd" 141 | else 142 | "build.sh" 143 | 144 | let fakeScriptPath = Path.Combine([|string solution.BaseDirectory; "build.fsx"|]) 145 | let launcherScriptPath = Path.Combine([|string solution.BaseDirectory; launcherScript|]) 146 | if File.Exists(fakeScriptPath) && File.Exists(launcherScriptPath) then 147 | let fakeScript = File.ReadAllText fakeScriptPath 148 | 149 | Regex.Matches(fakeScript, "Target \"([\\w.]+)\"") 150 | |> Seq.cast 151 | |> Seq.choose(fun x -> let (matched, rank) = matcher.CalcMatchRank ("FAKE " + x.Groups.[1].Value) 152 | match matched with 153 | | true -> Some (solution, x, rank, launcherScriptPath) 154 | | _ -> None) 155 | |> Seq.iter addResult } 156 | |> Async.Start ), token) 157 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Properties/AddinInfo.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | open Mono.Addins 3 | 4 | [] 9 | 10 | [] 11 | [] 12 | [] 13 | 14 | [] 15 | [] 16 | [] 17 | [] 18 | [] 19 | () -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Services/FileService.fs: -------------------------------------------------------------------------------- 1 |  2 | namespace MonoDevelop.FSharp 3 | open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library 4 | open System.IO 5 | open System.Threading 6 | open MonoDevelop.Ide 7 | open MonoDevelop.Ide.Gui 8 | open MonoDevelop.Core 9 | open MonoDevelop.Ide.TypeSystem 10 | open ExtCore.Control 11 | type Version = int 12 | 13 | type FileSystem (defaultFileSystem : IFileSystem, openDocuments: unit -> Document seq) = 14 | let timestamps = new System.Collections.Generic.Dictionary() 15 | let getOpenDoc filename = 16 | let docs = openDocuments() 17 | docs |> Seq.tryFind(fun d -> d.FileName.FullPath.ToString() = filename) 18 | 19 | let getOpenDocContent (filename: string) = 20 | match getOpenDoc filename with 21 | | Some d -> 22 | let bytes = System.Text.Encoding.UTF8.GetBytes (d.Editor.Text) 23 | Some bytes 24 | | _ -> None 25 | 26 | static member IsAScript fileName = 27 | let ext = Path.GetExtension fileName 28 | [".fsx";".fsscript";".sketchfs"] |> List.exists ((=) ext) 29 | 30 | interface IFileSystem with 31 | member x.FileStreamReadShim fileName = 32 | getOpenDocContent fileName 33 | |> Option.map (fun bytes -> new MemoryStream (bytes) :> Stream) 34 | |> Option.getOrElse (fun () -> defaultFileSystem.FileStreamReadShim fileName) 35 | 36 | member x.ReadAllBytesShim fileName = 37 | getOpenDocContent fileName 38 | |> Option.getOrElse (fun () -> defaultFileSystem.ReadAllBytesShim fileName) 39 | 40 | member x.GetLastWriteTimeShim fileName = 41 | let r = maybe { 42 | let! doc = getOpenDoc fileName 43 | if doc.IsDirty then 44 | let key, newhash = fileName, doc.Editor.Text.GetHashCode() 45 | return match timestamps.TryGetValue (key) with 46 | | true, (hash, date) when hash = newhash -> date 47 | | _ -> let d = System.DateTime.Now 48 | timestamps.[key] <- (newhash,d) 49 | d 50 | else return! None 51 | } 52 | r |> Option.getOrElse (fun () -> defaultFileSystem.GetLastWriteTimeShim fileName) 53 | 54 | member x.GetTempPathShim() = defaultFileSystem.GetTempPathShim() 55 | member x.FileStreamCreateShim fileName = defaultFileSystem.FileStreamCreateShim fileName 56 | member x.FileStreamWriteExistingShim fileName = defaultFileSystem.FileStreamWriteExistingShim fileName 57 | member x.GetFullPathShim fileName = defaultFileSystem.GetFullPathShim fileName 58 | member x.IsInvalidPathShim fileName = defaultFileSystem.IsInvalidPathShim fileName 59 | member x.IsPathRootedShim fileName = defaultFileSystem.IsPathRootedShim fileName 60 | member x.SafeExists fileName = defaultFileSystem.SafeExists fileName 61 | member x.FileDelete fileName = defaultFileSystem.FileDelete fileName 62 | member x.AssemblyLoadFrom fileName = defaultFileSystem.AssemblyLoadFrom fileName 63 | member x.AssemblyLoad(assemblyName) = defaultFileSystem.AssemblyLoad assemblyName 64 | 65 | module FileService = 66 | let supportedFileExtensions = 67 | [".fsscript"; ".fs"; ".fsx"; ".fsi"; ".sketchfs"] 68 | 69 | /// Is the specified extension supported F# file? 70 | let supportedFileName fileName = 71 | if fileName = null then 72 | false 73 | else 74 | let ext = Path.GetExtension(fileName).ToLower() 75 | supportedFileExtensions 76 | |> List.exists ((=) ext) 77 | 78 | let isInsideFSharpFile () = 79 | if IdeApp.Workbench.ActiveDocument = null || 80 | IdeApp.Workbench.ActiveDocument.FileName.FileName = null then false 81 | else 82 | let file = IdeApp.Workbench.ActiveDocument.FileName.ToString() 83 | supportedFileName (file) 84 | 85 | let supportedFilePath (filePath:FilePath) = 86 | supportedFileName (filePath.ToString()) 87 | 88 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Services/InteractiveSession.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open System.Reflection 5 | open System.IO 6 | open System.Diagnostics 7 | open MonoDevelop.Ide 8 | open MonoDevelop.Ide.CodeCompletion 9 | open MonoDevelop.Core 10 | open Newtonsoft.Json 11 | 12 | type CompletionData = { 13 | displayText: string 14 | completionText: string 15 | category: string 16 | icon: string 17 | overloads: CompletionData list 18 | description: string 19 | } 20 | 21 | type InteractiveSession() = 22 | let (|Completion|_|) (command: string) = 23 | if command.StartsWith("completion ") then 24 | let payload = command.[11..] 25 | Some (JsonConvert.DeserializeObject payload) 26 | else 27 | None 28 | 29 | let (|Tooltip|_|) (command: string) = 30 | if command.StartsWith("tooltip ") then 31 | let payload = command.[8..] 32 | Some (JsonConvert.DeserializeObject payload) 33 | else 34 | None 35 | 36 | let (|ParameterHints|_|) (command: string) = 37 | if command.StartsWith("parameter-hints ") then 38 | let payload = command.[16..] 39 | Some (JsonConvert.DeserializeObject payload) 40 | else 41 | None 42 | 43 | let path = "\"" + Path.Combine(Reflection.Assembly.GetExecutingAssembly().Location |> Path.GetDirectoryName, "MonoDevelop.FSharpInteractive.Service.exe") + "\"" 44 | let mutable waitingForResponse = false 45 | 46 | let fsiProcess = 47 | let processName = 48 | if Environment.runningOnMono then Environment.getMonoPath() else path 49 | 50 | let arguments = 51 | if Environment.runningOnMono then path else null 52 | 53 | let startInfo = 54 | new ProcessStartInfo 55 | (FileName = processName, UseShellExecute = false, Arguments = arguments, 56 | RedirectStandardError = true, CreateNoWindow = true, RedirectStandardOutput = true, 57 | RedirectStandardInput = true, StandardErrorEncoding = Text.Encoding.UTF8, StandardOutputEncoding = Text.Encoding.UTF8) 58 | 59 | try 60 | Process.Start(startInfo) 61 | with e -> 62 | LoggingService.LogDebug (sprintf "Interactive: Error %s" (e.ToString())) 63 | reraise() 64 | 65 | let textReceived = Event<_>() 66 | let promptReady = Event<_>() 67 | 68 | let sendCommand(str:string) = 69 | waitingForResponse <- true 70 | LoggingService.LogDebug (sprintf "Interactive: sending %s" str) 71 | let stream = fsiProcess.StandardInput.BaseStream 72 | let bytes = Text.Encoding.UTF8.GetBytes(str + "\n") 73 | stream.Write(bytes,0,bytes.Length) 74 | stream.Flush() 75 | 76 | let completionsReceivedEvent = new Event() 77 | let tooltipReceivedEvent = new Event() 78 | let parameterHintReceivedEvent = new Event() 79 | do 80 | fsiProcess.OutputDataReceived 81 | |> Event.filter (fun de -> de.Data <> null) 82 | |> Event.add (fun de -> 83 | LoggingService.logDebug "Interactive: received %s" de.Data 84 | if de.Data.Trim() = "SERVER-PROMPT>" then 85 | promptReady.Trigger() 86 | elif de.Data.Trim() <> "" then 87 | if waitingForResponse then waitingForResponse <- false 88 | textReceived.Trigger(de.Data + "\n")) 89 | 90 | fsiProcess.ErrorDataReceived.Subscribe(fun de -> 91 | if not (String.isNullOrEmpty de.Data) then 92 | try 93 | match de.Data with 94 | | Completion completions -> 95 | completionsReceivedEvent.Trigger completions 96 | | Tooltip tooltip -> 97 | tooltipReceivedEvent.Trigger tooltip 98 | | ParameterHints hints -> 99 | parameterHintReceivedEvent.Trigger hints 100 | | _ -> LoggingService.logDebug "[fsharpi] don't know how to process command %s" de.Data 101 | 102 | with 103 | | :? JsonException -> 104 | LoggingService.logError "[fsharpi] - error deserializing error stream - %s" de.Data 105 | ) |> ignore 106 | 107 | fsiProcess.EnableRaisingEvents <- true 108 | 109 | member x.Interrupt() = 110 | LoggingService.logDebug "Interactive: Break!" 111 | 112 | member x.CompletionsReceived = completionsReceivedEvent.Publish 113 | member x.TooltipReceived = tooltipReceivedEvent.Publish 114 | member x.ParameterHintReceived = parameterHintReceivedEvent.Publish 115 | 116 | member x.StartReceiving() = 117 | fsiProcess.BeginOutputReadLine() 118 | fsiProcess.BeginErrorReadLine() 119 | 120 | member x.TextReceived = textReceived.Publish 121 | member x.PromptReady = promptReady.Publish 122 | 123 | member x.Kill() = 124 | if not fsiProcess.HasExited then 125 | x.SendInput "#q;;" 126 | for i in 0 .. 10 do 127 | if not fsiProcess.HasExited then 128 | LoggingService.logDebug "Interactive: waiting for process exit after #q... %d" (i*200) 129 | fsiProcess.WaitForExit(200) |> ignore 130 | 131 | if not fsiProcess.HasExited then 132 | fsiProcess.Kill() 133 | for i in 0 .. 10 do 134 | if not fsiProcess.HasExited then 135 | LoggingService.logDebug "Interactive: waiting for process exit after kill... %d" (i*200) 136 | fsiProcess.WaitForExit(200) |> ignore 137 | 138 | member x.SendInput input = 139 | for line in String.getLines input do 140 | sendCommand ("input " + line) 141 | 142 | member x.SendCompletionRequest input column = 143 | sendCommand (sprintf "completion %d %s" column input) 144 | 145 | member x.SendParameterHintRequest input column = 146 | sendCommand (sprintf "parameter-hints %d %s" column input) 147 | 148 | member x.SendTooltipRequest input = 149 | sendCommand (sprintf "tooltip %s" input) 150 | 151 | member x.Exited = fsiProcess.Exited 152 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Services/OrderAssemblyReferences.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System.Reflection 4 | open System 5 | open Mono.Cecil 6 | 7 | module Object = 8 | let eqHack (f: 'a -> 'b) (x: 'a) (yobj: Object) : Boolean = 9 | match yobj with 10 | | :? 'a as y -> f x = f y 11 | | _ -> false 12 | 13 | let compHack (f: 'a -> 'b) (x: 'a) (yobj: Object) : Int32 = 14 | match yobj with 15 | | :? 'a as y -> compare (f x) (f y) 16 | | _ -> invalidArg "yobj" "Cannot compare elements of incompatible types" 17 | 18 | type Digraph<'n> when 'n : comparison = 19 | Map<'n, Set<'n>> 20 | 21 | module Digraph = 22 | 23 | let addNode (n: 'n) (g: Digraph<'n>) : Digraph<'n> = 24 | match Map.tryFind n g with 25 | | None -> Map.add n Set.empty g 26 | | Some _ -> g 27 | 28 | let addEdge ((n1, n2): 'n * 'n) (g: Digraph<'n>) : Digraph<'n> = 29 | let g' = 30 | match Map.tryFind n2 g with 31 | | None -> addNode n2 g 32 | | Some _ -> g 33 | match Map.tryFind n1 g with 34 | | None -> Map.add n1 (Set.singleton n2) g' 35 | | Some ns -> Map.add n1 (Set.add n2 ns) g' 36 | 37 | let nodes (g: Digraph<'n>) : List<'n> = 38 | Map.fold (fun xs k _ -> k::xs) [] g 39 | 40 | let roots (g: Digraph<'n>) : List<'n> = 41 | List.filter (fun n -> not (Map.exists (fun _ v -> Set.contains n v) g)) (nodes g) 42 | 43 | let topSort (h: Digraph<'n>) : List<'n> = 44 | let rec dfs (g: Digraph<'n>, order: List<'n>, rts: List<'n>) : List<'n> = 45 | if List.isEmpty rts then 46 | order 47 | else 48 | let n = List.head rts 49 | let order' = n::order 50 | let g' = Map.remove n g 51 | let rts' = roots g' 52 | dfs (g', order', rts') 53 | dfs (h, [], roots h) 54 | 55 | [] 56 | [] 57 | [] 58 | type AssemblyRef = 59 | { 60 | Path: String 61 | Assembly: AssemblyDefinition 62 | Name: String 63 | } 64 | 65 | member this.show = this.ToString () 66 | 67 | override this.Equals (obj: Object) : bool = 68 | Object.eqHack (fun (a:AssemblyRef) -> a.Name) this obj 69 | 70 | override this.GetHashCode () = 71 | hash this.Name 72 | 73 | interface System.IComparable with 74 | member this.CompareTo (obj: Object) = 75 | Object.compHack (fun (p:AssemblyRef) -> p.Name) this obj 76 | 77 | override x.ToString () = x.Path 78 | 79 | [] 80 | type OrderAssemblyReferences () = 81 | 82 | let mkGraph (seeds: seq) : Digraph = 83 | 84 | let findRef (s: seq) (m: AssemblyNameReference) = 85 | match Seq.tryFind (fun r -> r.Name = m.FullName) seeds with 86 | | None -> s 87 | | Some ar -> Seq.append (Seq.singleton ar) s 88 | 89 | let processNode (g: Digraph) (n: AssemblyRef) = 90 | let depNames = n.Assembly.MainModule.AssemblyReferences.ToArray() 91 | let depRefs = Array.fold findRef Seq.empty depNames 92 | Seq.fold (fun h c -> Digraph.addEdge (n, c) h) g depRefs 93 | 94 | let rec fixpoint (g: Digraph) = 95 | let ns = Digraph.nodes g 96 | let g' = List.fold processNode g ns 97 | if g = g' then g else fixpoint g' 98 | 99 | fixpoint (Seq.fold (fun g s -> Digraph.addNode s g) Map.empty seeds) 100 | 101 | let mkAssemblyRef (t: String) = 102 | let assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(t) 103 | { 104 | Path = t 105 | Assembly = assemblyDefinition 106 | Name = assemblyDefinition.FullName 107 | } 108 | 109 | ///Orders the passed in array of assembly references in dependency order 110 | member x.Order(rs: String[]) = 111 | let asmRefs = Array.map mkAssemblyRef rs 112 | let graph = mkGraph asmRefs 113 | let ordering = Digraph.topSort graph 114 | ordering 115 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Services/Parameters.fs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------- 2 | // Serializable types that store F# project parameters (build order) and 3 | // F# compiler parameters (debug mode, tail-calls, etc.) 4 | // -------------------------------------------------------------------------------------- 5 | 6 | namespace MonoDevelop.FSharp 7 | 8 | open System 9 | open MonoDevelop.Projects 10 | open MonoDevelop.Core.Serialization 11 | 12 | /// Serializable type respresnting F# compiler parameters 13 | type FSharpCompilerParameters() = 14 | inherit MonoDevelop.Projects.DotNetCompilerParameters() 15 | 16 | [] 17 | let mutable optimize = true 18 | 19 | [] 20 | let mutable generateTailCalls = false 21 | 22 | [] 23 | let mutable noStdLib = false 24 | 25 | [] 26 | let mutable defineConstants = "" 27 | 28 | [] 29 | let mutable otherFlags = "" 30 | 31 | [] 32 | let mutable documentationFile = "" 33 | 34 | [] 35 | let mutable platformTarget = "anycpu" 36 | 37 | member x.Optimize with get () = optimize and set v = optimize <- v 38 | member x.GenerateTailCalls with get () = generateTailCalls and set v = generateTailCalls <- v 39 | override x.NoStdLib with get () = noStdLib and set v = noStdLib <- v 40 | member x.DefineConstants with get () = defineConstants and set v = defineConstants <- v 41 | member x.OtherFlags with get () = otherFlags and set v = otherFlags <- v 42 | member x.DocumentationFile with get () = documentationFile and set v = documentationFile <- v 43 | member x.PlatformTarget with get () = platformTarget and set v = platformTarget <- v 44 | 45 | override x.AddDefineSymbol(symbol) = 46 | if System.String.IsNullOrEmpty x.DefineConstants then 47 | x.DefineConstants <- symbol 48 | else 49 | x.DefineConstants <- x.DefineConstants + ";" + symbol 50 | 51 | override x.RemoveDefineSymbol(symbol) = 52 | if x.DefineConstants = symbol then 53 | x.DefineConstants <- "" 54 | elif (String.IsNullOrWhiteSpace >> not) x.DefineConstants then 55 | x.DefineConstants <- x.DefineConstants.Replace(";" + symbol, "") 56 | 57 | override x.GetDefineSymbols () = 58 | if String.IsNullOrWhiteSpace x.DefineConstants then 59 | Seq.empty 60 | else 61 | x.DefineConstants.Split (';', ',', ' ', '\t') 62 | |> Seq.where (String.IsNullOrWhiteSpace >> not) 63 | 64 | override x.CreateCompilationOptions () = 65 | null //TODO 66 | 67 | override x.CreateParseOptions (_) = 68 | null //TODO 69 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Services/Parser.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | 3 | open System 4 | open Microsoft.FSharp.Compiler.SourceCodeServices 5 | open Microsoft.FSharp.Compiler 6 | open System.Globalization 7 | open MonoDevelop.Core 8 | 9 | // -------------------------------------------------------------------------------------- 10 | /// Parsing utilities for IntelliSense (e.g. parse identifier on the left-hand side 11 | /// of the current cursor location etc.) 12 | module Parsing = 13 | let inline private tryGetLexerSymbolIslands sym = 14 | match sym.Text with "" -> None | _ -> Some (sym.RightColumn, sym.Text.Split '.' |> Array.toList) 15 | 16 | // Parsing - find the identifier around the current location 17 | // (we look for full identifier in the backward direction, but only 18 | // for a short identifier forward - this means that when you hover 19 | // 'B' in 'A.B.C', you will get intellisense for 'A.B' module) 20 | let findIdents col lineStr lookupType = 21 | if lineStr = "" then None 22 | else 23 | Lexer.getSymbol lineStr 0 col lineStr lookupType [||] Lexer.singleLineQueryLexState 24 | |> Option.bind tryGetLexerSymbolIslands 25 | 26 | let findLongIdentsAndResidue (col, lineStr:string) = 27 | let lineStr = lineStr.Substring(0, col) 28 | 29 | match Lexer.getSymbol lineStr 0 col lineStr SymbolLookupKind.ByLongIdent [||] Lexer.singleLineQueryLexState with 30 | | Some sym -> 31 | match sym.Text with 32 | | "" -> [], "" 33 | | text -> 34 | let res = text.Split '.' |> List.ofArray |> List.rev 35 | if lineStr.[col - 1] = '.' then res |> List.rev, "" 36 | else 37 | match res with 38 | | head :: tail -> tail |> List.rev, head 39 | | [] -> [], "" 40 | | _ -> [], "" 41 | 42 | let findResidue (col, lineStr:string) = 43 | // scan backwards until we find the start of the current symbol 44 | let rec loop index = 45 | if index = 0 then 46 | 0 47 | elif lineStr.[index - 1] = '.' || lineStr.[index - 1] = ' ' then 48 | index 49 | else 50 | loop (index - 1) 51 | 52 | let index = loop col 53 | lineStr.[index..] -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/AssemblyInfo.xft.xml: -------------------------------------------------------------------------------- 1 | 2 | 46 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/EmptyFSharpScript.xft.xml: -------------------------------------------------------------------------------- 1 |  2 | 19 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/EmptyFSharpSignature.xft.xml: -------------------------------------------------------------------------------- 1 |  2 | 23 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/EmptyFSharpSource.xft.xml: -------------------------------------------------------------------------------- 1 |  2 | 19 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/FSharpConsoleProject.xpt.xml: -------------------------------------------------------------------------------- 1 | 2 | 50 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/FSharpGtkProject.xpt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 85 | 86 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/FSharpLibraryProject.xpt.xml: -------------------------------------------------------------------------------- 1 | 2 | 54 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/FSharpNUnitLibraryProject.xpt.xml: -------------------------------------------------------------------------------- 1 | 2 | 59 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/FSharpNUnitTestType.xft.xml: -------------------------------------------------------------------------------- 1 | 2 | 32 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/PortableLibrary.xpt.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/Templates/SharedAssetsProject.xpt.xml: -------------------------------------------------------------------------------- 1 | 2 | 37 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/UnformattedTextFileDescriptionTemplate.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharp 2 | open System 3 | open System.Collections.Generic 4 | open System.IO 5 | open System.Text.RegularExpressions 6 | open MonoDevelop.Ide.Templates 7 | open MonoDevelop.Core 8 | open MonoDevelop.Projects 9 | open MonoDevelop.Ide.StandardHeader 10 | open System.Text 11 | open MonoDevelop.Ide.Gui.Content 12 | open ExtCore 13 | 14 | type UnformattedTextFileDescriptionTemplate() = 15 | inherit TextFileDescriptionTemplate() 16 | 17 | let getDefaultNs (potential:string) = 18 | let sb = StringBuilder potential.Length 19 | 20 | for c in potential do 21 | match c with 22 | | c when Char.IsLetter c || c = '_' || c = '.' -> 23 | sb.Append c |> ignore 24 | | c when Char.IsDigit c && sb.LastCharacterIs ((=) '.') || sb.Length = 0 -> 25 | sb.Append '_' |> ignore 26 | sb.Append c |> ignore 27 | | c when Char.IsDigit c -> 28 | sb.Append c |> ignore 29 | | _ -> 30 | sb.Append '_' |> ignore 31 | 32 | if sb.LastCharacterIs ((=) '.') then sb.Remove (sb.Length - 1, 1) |> ignore 33 | sb.ToString () 34 | 35 | override x.ModifyTags (policyParent, project, language, identifier, fileName, tags) = 36 | base.ModifyTags (policyParent, project, language, identifier, fileName, &tags) 37 | 38 | let ns = project |> function null -> "Application" | project -> getDefaultNs project.Name 39 | let getSafeName str = 40 | let regex = new Regex("[^a-zA-Z0-9.]") 41 | regex.Replace(str, "") 42 | 43 | if tags.ContainsKey("Namespace") then 44 | tags.["Namespace"] <- ns 45 | 46 | if tags.ContainsKey("AppName") then 47 | tags.["AppName"] <- getSafeName tags.["SolutionName"] 48 | 49 | override x.CreateFileContent(policyParent, project, language, fileName, identifier) = 50 | let tags = new Dictionary<_, _> () 51 | x.ModifyTags (policyParent, project, language, identifier, fileName, ref tags) 52 | 53 | let ms = new MemoryStream () 54 | 55 | let bom = Encoding.UTF8.GetPreamble () 56 | ms.Write (bom, 0, bom.Length) 57 | 58 | if x.AddStandardHeader then 59 | let header = StandardHeaderService.GetHeader (policyParent, fileName, true) 60 | let data = System.Text.Encoding.UTF8.GetBytes header 61 | ms.Write (data, 0, data.Length) 62 | 63 | let doc = 64 | let content = x.CreateContent (project, tags, language) 65 | let content = StringParserService.Parse (content, tags) 66 | new Mono.TextEditor.TextDocument (Text = content) 67 | 68 | let textPolicy = 69 | match policyParent with 70 | | null -> Policies.PolicyService.GetDefaultPolicy "text/plain" 71 | | p -> p.Policies.Get "text/plain" 72 | 73 | let eolMarker = TextStylePolicy.GetEolMarker textPolicy.EolMarker 74 | let eolMarkerBytes = Encoding.UTF8.GetBytes eolMarker 75 | 76 | 77 | for line in doc.Lines do 78 | let lineText = 79 | let lt = doc.GetTextAt (line.Offset, line.Length) 80 | if textPolicy.TabsToSpaces then 81 | let tab = String.replicate textPolicy.TabWidth " " 82 | lt.Replace ("\t", tab) 83 | else lt 84 | 85 | let data = Encoding.UTF8.GetBytes lineText 86 | ms.Write (data, 0, data.Length) 87 | ms.Write (eolMarkerBytes, 0, eolMarkerBytes.Length) 88 | 89 | ms.Position <- 0L 90 | ms :> _ 91 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/paket.references: -------------------------------------------------------------------------------- 1 | ExtCore 2 | Fantomas 3 | FSharp.Compiler.CodeDom 4 | Mono.Cecil 5 | Newtonsoft.Json -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/templates.AssemblyInfo.xft.xml: -------------------------------------------------------------------------------- 1 | 2 | 47 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpBinding/templates.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PreserveNewest 5 | 6 | 7 | PreserveNewest 8 | 9 | 10 | PreserveNewest 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | PreserveNewest 17 | 18 | 19 | PreserveNewest 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | PreserveNewest 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | PreserveNewest 38 | 39 | 40 | PreserveNewest 41 | 42 | 43 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpi.Service/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharpi.Service 2 | open System.Reflection 3 | open System.Runtime.CompilerServices 4 | 5 | [] 6 | [] 7 | [] 8 | [] 9 | [] 10 | [] 11 | [] 12 | 13 | // The assembly version has the format {Major}.{Minor}.{Build}.{Revision} 14 | 15 | [] 16 | 17 | //[] 18 | //[] 19 | 20 | () 21 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpi.Service/Program.fs: -------------------------------------------------------------------------------- 1 | namespace MonoDevelop.FSharpInteractive 2 | open System 3 | open System.IO 4 | open System.Text 5 | open Newtonsoft.Json 6 | open Microsoft.FSharp.Compiler.SourceCodeServices 7 | open Microsoft.FSharp.Compiler.Interactive.Shell 8 | 9 | open MonoDevelop.FSharp.Shared 10 | /// Wrapper for fsi with support for returning completions 11 | module CompletionServer = 12 | [] 13 | let main argv = 14 | let inStream = Console.In 15 | let outStream = Console.Out 16 | let server = "MonoDevelop" + Guid.NewGuid().ToString("n") 17 | 18 | // This flag makes fsi send the SERVER-PROMPT> prompt 19 | // once it's output the header 20 | let args = "--fsi-server:" + server + " " 21 | let argv = [| "--readline-"; args |] 22 | 23 | let serializer = JsonSerializer.Create() 24 | 25 | let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration(Microsoft.FSharp.Compiler.Interactive.Settings.fsi, true) 26 | 27 | let fsiSession = FsiEvaluationSession.Create(fsiConfig, argv, inStream, outStream, outStream, true) 28 | 29 | let (|Input|_|) (command: string) = 30 | if command.StartsWith("input ") then 31 | Some(command.[6..]) 32 | else 33 | None 34 | 35 | let (|Tooltip|_|) (command: string) = 36 | if command.StartsWith("tooltip ") then 37 | Some(command.[8..]) 38 | else 39 | None 40 | 41 | let (|Completion|_|) (command: string) = 42 | if command.StartsWith("completion ") then 43 | let input = command.[11..] 44 | let splitIndex = input.IndexOf(" ") 45 | if (splitIndex = -1) then 46 | None 47 | else 48 | let colStr = input.[0..splitIndex] 49 | let success, col = Int32.TryParse colStr 50 | if success then 51 | Some (col, input.[splitIndex..]) 52 | else 53 | None 54 | else 55 | None 56 | 57 | let (|ParameterHints|_|) (command: string) = 58 | if command.StartsWith("parameter-hints ") then 59 | let input = command.[16..] 60 | let splitIndex = input.IndexOf(" ") 61 | if (splitIndex = -1) then 62 | None 63 | else 64 | let colStr = input.[0..splitIndex] 65 | let success, col = Int32.TryParse colStr 66 | if success then 67 | Some (col, input.[splitIndex..]) 68 | else 69 | None 70 | else 71 | None 72 | 73 | let writeOutput (s:string) = 74 | async { 75 | do! outStream.WriteLineAsync s |> Async.AwaitTask 76 | } 77 | 78 | let writeData commandType obj = 79 | async { 80 | let json = JsonConvert.SerializeObject obj 81 | do! Console.Error.WriteLineAsync (commandType + " " + json) |> Async.AwaitTask 82 | } 83 | 84 | let rec main(currentInput) = 85 | let parseInput() = 86 | async { 87 | let! command = inStream.ReadLineAsync() |> Async.AwaitTask 88 | 89 | match command with 90 | | Input input -> 91 | if input.EndsWith(";;") then 92 | try 93 | let result, warnings = fsiSession.EvalInteractionNonThrowing (currentInput + "\n" + input) 94 | match result with 95 | | Choice1Of2 () -> () 96 | | Choice2Of2 exn -> do! writeOutput (exn |> string) 97 | for w in warnings do 98 | do! writeOutput (sprintf "%s at %d,%d" w.Message w.StartLineAlternate w.StartColumn) 99 | 100 | if not (input.StartsWith "#silentCd") then 101 | do! writeOutput "SERVER-PROMPT>" 102 | with 103 | | exn -> do! writeOutput (exn |> string) 104 | return "" 105 | else 106 | return currentInput + "\n" + input 107 | | Tooltip filter -> 108 | let! tooltip = Completion.getCompletionTooltip filter 109 | do! writeData "tooltip" tooltip 110 | return currentInput 111 | | Completion context -> 112 | let col, lineStr = context 113 | let! results = Completion.getCompletions(fsiSession, lineStr, col) 114 | do! writeData "completion" results 115 | return currentInput 116 | | ParameterHints context -> 117 | let col, lineStr = context 118 | let! results = Completion.getParameterHints(fsiSession, lineStr, col) 119 | do! writeData "parameter-hints" results 120 | return currentInput 121 | | _ -> do! writeOutput (sprintf "Could not parse command - %s" command) 122 | return currentInput 123 | } 124 | let currentInput = parseInput() |> Async.RunSynchronously 125 | main(currentInput) 126 | 127 | Console.SetOut outStream 128 | main("") 129 | 130 | 0 // return an integer exit code 131 | 132 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpi.Service/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /MonoDevelop.FSharpi.Service/lib/FSharp.Compiler.Interactive.Settings.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/zarchive-xamarin-monodevelop-fsharp-addin/43dc90dbb354f06458dc7f48614716533f8735c6/MonoDevelop.FSharpi.Service/lib/FSharp.Compiler.Interactive.Settings.dll -------------------------------------------------------------------------------- /MonoDevelop.FSharpi.Service/paket.references: -------------------------------------------------------------------------------- 1 | ExtCore 2 | FSharp.Compiler.Service 3 | Newtonsoft.Json 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # __This repo is now redundant.__ 2 | # The F# plugin is now contained within the [monodevelop repo](https://github.com/mono/monodevelop/tree/master/main/external/fsharpbinding) 3 | 4 | # F# Language Support for MonoDevelop / Xamarin Studio 5 | 6 | This project contains advanced editing support for the F# addin in MonoDevelop and Xamarin Studio](monodevelop/README.md) 7 | 8 | ## Features 9 | * Code completion 10 | * Syntax highlighting 11 | * Tooltips 12 | * Debugging 13 | * Target .NET 3.5, 4.0, 4.5 14 | * F# Interactive scripting (Alt-Enter execution) 15 | * Templates (Console Application, Library, Tutorial Project, Gtk Project, iOS, Android) 16 | * Makefile support 17 | * Supports F# 3.0 type providers (requires F# 3.0) 18 | * xbuild support for Visual Studio .fsproj and .sln files without change (requires Mono 3.0 and F# 3.0) 19 | 20 | Requires MonoDevelop or Xamarin Studio 4.0.13 and later versions 21 | 22 | ### Prerequisites 23 | 24 | To use F# language support please ensure that you have F# installed on your system, for details on this please see http://fsharp.org 25 | 26 | ### Installation 27 | 28 | First check install MonoDevelop/Xamarin Studio. Check if F# support is already installed using the AddIn manager. 29 | MonoDevelop/Xamarin Studio 30 | --> Add-in manager 31 | --> Language Bindings 32 | --> Check for F# binding 33 | 34 | If so, just use it, no installation is required. 35 | 36 | If not, install the F# Language Binding via the AddIn manager. 37 | 38 | MonoDevelop/Xamarin Studio 39 | --> Add-in manager 40 | --> Gallery 41 | --> Language Bindings 42 | --> F# Language Binding 43 | 44 | 45 | ### Building and installing from scratch 46 | 47 | ### Build on Mac/Linux: 48 | 49 | Currently this repo is built against the `roslyn` branch of monodevelop and is actually referenced in the submodules via main/external/fsharbinding. One of the easiest ways of building is to clone monodevelop and work in the submodule directly: 50 | 51 | ```bash 52 | git clone git@github.com:mono/monodevelop -b roslyn --recursive 53 | cd monodevelop 54 | ./configure --profile=mac 55 | make 56 | ``` 57 | 58 | To configure and compile the addin seperatly then the following commands can be executed from the addin directory (/main/external/fsharpbining if cloning as part of monodevelop) 59 | 60 | ```bash 61 | ./configure.sh 62 | make 63 | make install 64 | ``` 65 | 66 | If MonoDevelop is installed in an unusual prefix you will need to invoke `configure.sh` with e.g. `--prefix=/path/to/prefix/lib/monodevelop`. Use `./configure.sh --help` to see a list of the paths searched by default. 67 | 68 | If you subsequently make changes to the add-in, you will need to `make install` again and restart MonoDevelop/Xamarin Studio. 69 | 70 | The first time you `make install` the AddIn you'll override Xamarin's official one and it will initially be set to disabled, so you need to go to the AddIn manager and ensure the F# AddIn is enabled. 71 | 72 | **Note:** One thing to check is the the version specified in `configure.fsx` is higher than the pre-installed version, if it's not then the local addin will not be loaded. 73 | 74 | For reference on Mac the locally installed addin is at the following location: ```/Users//Library/Application Support/XamarinStudio-6.0/LocalInstall/Addins/fsharpbinding/``` 75 | 76 | ### Build on Windows (builds and installs the Debug version into Xamarin Studio - adjust as needed) 77 | 78 | ```dos 79 | configure.bat 80 | build-and-install-debug.bat 81 | ``` 82 | 83 | If you subsequently make changes to the add-in, you will need to `build-and-install-debug.bat` again and restart MonoDevelop/Xamarin Studio. 84 | 85 | ### Can't get it to work? 86 | 87 | Don't give up! Add an issue to [bugzilla](https://bugzilla.xamarin.com/enter_bug.cgi?product=Xamarin%20Studio) using F# addin as the component name. Your issue will be seen by the developers. 88 | 89 | ### Notes for Developers 90 | 91 | Note: The MonoDevelop/Xamarin Studio developers have now incorporated the binding into all releases 92 | of MonoDevelop and Xamarin Studio. 93 | 94 | To check things are working try a few different things somewhat at random: 95 | - Check the F# templates are appearing 96 | - Create a console project (NOTE: retarget it to .NET 4.0 using right-click->options->General) 97 | - Check there are completion lists in the console project e.g. for 'System.' and 'System.Console.WriteLine(' and 'List.' 98 | - Check you can build the console project 99 | - Check you can run the console project 100 | - Check you can "debug-step-into" the console project 101 | - Check you can set a break point in the console project 102 | - Check there are type tips showing when you move the mouse over code identifiers 103 | - Load an existing .fsproj (e.g. see MonoDevelop.FSharpBinding/tests/projects/...) and check if completion works etc. 104 | - Run xbuild on a few .fsproj (this is nothing to do with the binding, it is just fsharp/fsharp) 105 | 106 | On Windows, the configuration creates the file `MonoDevelop.FSharpBinding\MonoDevelop.FSharp.windows.fsproj`. 107 | Be aware that this is not the original file, which is `MonoDevelop.FSharp.fsproj.orig`. The windows file is 108 | created automatically by the configuration script (`configure.bat`) 109 | 110 | On Mac/Linux, please develop using the 'Makefile' with Mono 3.0 and FSharp 3.1. 111 | 112 | To be able to debug the add-in in Xamarin Studio or Monodevelop, invoke `./configure.sh --debug` or `configure.bat --debug`. This adds the necessary .mdb files to the add-in. 113 | When configured with `--debug` you can simply `Start debugging` in Xamarin Studio. This will launch a debugged instance of Xamarin Studio. 114 | 115 | On Mac, if you make changes to the add-in after debugging, you will need to restart Xamarin Studio or MonoDevelop before rebuilding. 116 | 117 | Note that you can not build the add-in in release mode when configured with `--debug`. To build a release build, first `./configure.sh` without `--debug` 118 | 119 | 120 | On Mac/Linux, if you make changes to the binding, then loss of completion lists etc. can be disturbing and hard to debug. There are some debugging techniques. To launch MonoDevelop you can use the command: 121 | ``` 122 | /Applications/MonoDevelop.app/Contents/MacOS/MonoDevelop --new-window --no-redirect 123 | ``` 124 | or this command for Xamarin Studio: 125 | ``` 126 | "/Applications/Xamarin Studio.app/Contents/MacOS/XamarinStudio" --new-window --no-redirect 127 | ``` 128 | to enable some logging you can use 129 | 130 | export FSHARPBINDING_LOGGING=* 131 | 132 | On Windows you can generally use Visual Studio to help develop the binding. 133 | You can start Xamarin Studio or MonoDevelop under the debugger using the normal technique: 134 | 135 | devenv /debugexe "c:\Program Files (x86)\Xamarin Studio\bin\XamarinStudio.exe" 136 | 137 | 138 | ### Notes for People Preparing Releases 139 | 140 | Note the MonoDevelop/Xamarin Studio developers have incorporated the binding into all releases 141 | of MonoDevelop and Xamarin Studio. This section remains for reference. 142 | 143 | The MonoDevelop Addin mechanism can be hard to easily find information for so here are a couple of links to help get a better understanding. 144 | 145 | - The addin.xml installation schema description can be found [here](http://addins.monodevelop.com/Source/AddinProjectHelp?projectId=1) 146 | - Details about publishing an addin can be found [here](http://monodevelop.com/Developers/Articles/Publishing_an_Addin) 147 | 148 | The addin used to get released to http://addins.monodevelop.com under project 'FSharp' (project index 48). This is obsolete due to the addin being packaged as part of the Xamarin Studio release cycle. Manual updates can be done although this is only really relevant for linux. Raise an issue for more information or to discuss this. 149 | 150 | To build the .mpack files to upload to this site, use: 151 | 152 | cd monodevelop 153 | ./configure.sh 154 | make pack 155 | 156 | The pack file goes under pack/... 157 | 158 | The build is performed against the installed MonoDevelop or Xamarin Studio on your machine. 159 | 160 | For more information about F# see [The F# Software Foundation](http://fsharp.org). Join [The F# Open Source Group](http://fsharp.github.com). 161 | -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | #### 6.0.0 - 23.11.2015 2 | * BUGFIX: Fixed issue with highlighting of mutable bindings 3 | -------------------------------------------------------------------------------- /addin-project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | bin/FSharpBinding.dll 4 | MonoDevelop.FSharp.sln 5 | Debug 6 | 7 | 8 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | SETLOCAL 3 | 4 | cls 5 | 6 | .paket\paket.bootstrapper.exe 7 | if errorlevel 1 ( 8 | exit /b %errorlevel% 9 | ) 10 | 11 | .paket\paket.exe restore 12 | if errorlevel 1 ( 13 | exit /b %errorlevel% 14 | ) 15 | 16 | SET TARGET=Default 17 | 18 | IF NOT [%1]==[] (SET TARGET=%~1) 19 | 20 | "packages\FAKE\tools\Fake.exe" "build.fsx" "target="%TARGET%"" -------------------------------------------------------------------------------- /build.fsx: -------------------------------------------------------------------------------- 1 | #r @"./packages/FAKE/tools/FakeLib.dll" 2 | open Fake 3 | open System.IO 4 | 5 | let isWindows = (Path.DirectorySeparatorChar = '\\') 6 | let config = "Release" 7 | 8 | Target "Default" (fun _ -> 9 | MSBuildWithDefaults "Build" ["./MonoDevelop.FSharp.sln"] 10 | |> Log "AppBuild-Output: " 11 | ) 12 | 13 | let mdpath = "../../build/bin/mdtool.exe" 14 | 15 | let mdtool args = 16 | let result = 17 | if isWindows then 18 | Shell.Exec (mdpath, args) 19 | else 20 | Shell.Exec ("mono64", mdpath + " " + args) 21 | result |> ignore 22 | 23 | let test() = 24 | mdtool ("run-md-tests ../../external/fsharpbinding/MonoDevelop.FSharp.Tests/bin/" + config + "/MonoDevelop.FSharp.Tests.dll -labels") 25 | 26 | Target "Pack" (fun _ -> 27 | let dir = "pack/" + config 28 | if Directory.Exists dir then 29 | Directory.Delete (dir, true) 30 | Directory.CreateDirectory dir |> ignore 31 | mdtool ("setup pack bin/FSharpBinding.dll -d:pack/" + config) 32 | ) 33 | 34 | Target "Install" (fun _ -> 35 | let versionConfig = File.ReadAllLines("../../../version.config") 36 | let version = versionConfig.[0].Replace("Version=", "") 37 | mdtool ("setup install -y pack/" + config + "/MonoDevelop.FSharpBinding_" + version + ".mpack") 38 | ) 39 | 40 | Target "BuildAndTest" (fun _ -> 41 | test() 42 | ) 43 | 44 | Target "Test" (fun _ -> 45 | test() 46 | ) 47 | 48 | Target "Run" (fun _ -> 49 | Shell.Exec ("make", "run", "../..") |> ignore 50 | ) 51 | 52 | "Default" 53 | ==> "BuildAndTest" 54 | 55 | "Default" 56 | ==> "Run" 57 | 58 | "Pack" 59 | ==> "Install" 60 | 61 | RunTargetOrDefault "Default" 62 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if test "$OS" = "Windows_NT" 3 | then 4 | # use .Net 5 | 6 | .paket/paket.bootstrapper.exe 7 | exit_code=$? 8 | if [ $exit_code -ne 0 ]; then 9 | exit $exit_code 10 | fi 11 | 12 | .paket/paket.exe restore 13 | exit_code=$? 14 | if [ $exit_code -ne 0 ]; then 15 | exit $exit_code 16 | fi 17 | 18 | [ ! -e build.fsx ] && .paket/paket.exe update 19 | [ ! -e build.fsx ] && packages/FAKE/tools/FAKE.exe init.fsx 20 | packages/FAKE/tools/FAKE.exe $@ --fsiargs -d:MONO build.fsx 21 | else 22 | # use mono 23 | mono .paket/paket.bootstrapper.exe 24 | exit_code=$? 25 | if [ $exit_code -ne 0 ]; then 26 | exit $exit_code 27 | fi 28 | 29 | mono .paket/paket.exe restore 30 | exit_code=$? 31 | if [ $exit_code -ne 0 ]; then 32 | exit $exit_code 33 | fi 34 | 35 | [ ! -e build.fsx ] && mono .paket/paket.exe update 36 | [ ! -e build.fsx ] && mono packages/FAKE/tools/FAKE.exe init.fsx 37 | mono packages/FAKE/tools/FAKE.exe $@ --fsiargs -d:MONO build.fsx 38 | fi 39 | -------------------------------------------------------------------------------- /configure.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | echo "Configuring..." 3 | # MonoDevelop's configure script expects to find a configure script in each folder 4 | -------------------------------------------------------------------------------- /launch.bat: -------------------------------------------------------------------------------- 1 | SETLOCAL 2 | SET MONODEVELOP_DEV_ADDINS=%~dp0bin 3 | CD ..\..\build 4 | CALL bin\MonoDevelop.exe --no-redirect 5 | -------------------------------------------------------------------------------- /paket.dependencies: -------------------------------------------------------------------------------- 1 | source https://nuget.org/api/v2/ 2 | 3 | nuget ExtCore framework: >= net40 4 | nuget FSharp.Compiler.Service = 2.0.0.6 5 | nuget FSharp.Core = 4.0.0.1 6 | nuget Fantomas framework: >= net45 7 | nuget FSharp.Compiler.CodeDom 0.9.2 framework: >= net40 8 | nuget Mono.Cecil framework: >= net40 9 | nuget FAKE 10 | nuget Newtonsoft.Json 11 | -------------------------------------------------------------------------------- /paket.lock: -------------------------------------------------------------------------------- 1 | NUGET 2 | remote: https://www.nuget.org/api/v2 3 | specs: 4 | ExtCore (0.8.45) - framework: >= net40 5 | FAKE (4.22.4) 6 | Fantomas (2.0.2) - framework: >= net45 7 | FSharp.Compiler.Service (>= 1.4.0.6) 8 | FSharp.Compiler.CodeDom (0.9.2) - framework: >= net40 9 | FSharp.Compiler.Service (2.0.0.6) 10 | FSharp.Core (4.0.0.1) 11 | Mono.Cecil (0.9.6.1) - framework: >= net40 12 | Newtonsoft.Json (8.0.3) 13 | --------------------------------------------------------------------------------