Browse Source

.csproj/.vbproj files can now be opened directly (.sln is automatically created)

Files from command line arguments are opened instead of the start page.
Made GetWorkbench() in ParserUpdateThread thread-safe. (fixes NullReferenceException when closing files while the parser thread is running).

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@234 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
8545cf82a6
  1. 62
      doc/technotes/Versioning.html
  2. 4
      src/AddIns/Misc/StartPage/Project/StartPage.addin
  3. 53
      src/Main/Base/Project/Src/Commands/AutostartCommands.cs
  4. 8
      src/Main/Base/Project/Src/Commands/FileMenuCommands.cs
  5. 3
      src/Main/Base/Project/Src/Gui/IWorkbenchLayout.cs
  6. 8
      src/Main/Base/Project/Src/Gui/Workbench/DefaultWorkbench.cs
  7. 14
      src/Main/Base/Project/Src/Services/File/RecentOpen.cs
  8. 20
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
  9. 28
      src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs
  10. 12
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CodeCompletionDataUsageCache.cs
  11. 42
      src/Main/Core/Project/Src/AddInTree/AddInTree.cs
  12. 12
      src/Main/StartUp/Project/SharpDevelopMain.cs

62
doc/technotes/Versioning.html

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
<html>
<head>
<title>Assembly Versioning</title>
<meta name="Author" content="Daniel Grunwald">
</head>
<body>
<h1>Assembly Versioning in SharpDevelop</h1>
<h2>How the versions are set</h2>
<p>
The assemblyInfo.cs files are updated by the tool "UpdateAssemblyInfo".
"UpdateAssemblyInfo Startup" runs as pre-compile target and always set's
SharpDevelop.exe's revision to the subversion revision number. That
number is displayed in the splash screen, error dialog and about dialog.
</p>
<p>
The libraries (Core, SharpDevelop, TextEditor, NRefactoring, Addins) however
are a little different. Their assemblyinfos are not "templated" like the one in
Startup, but directly included in the repository.
However, we don't want to re-commit them on every commit.
Therefore, the versioning is different.
</p>
<p>
"ReleaseBuild.bat" updates their AssemblyInfo, too; but the normal "build.bat" doesn't.
In the repository, they are always included with the version number "2.0.0.1".
When doing a releasebuild, this version is replaced by the major version from
Startup + the subversion revision number. (That means if you want to change from
"2.0.0.x" to "2.0.1.x", you only have to change Startup\AssemblyInfo.<b>template</b>)
</p>
<p>
If you now want to commit local repository changes, you have to revert the
assembly infos back to "2.0.0.1" first. This is done by the file "resetAssemblyInfo.bat".
</p>
<p>
So in conclusion, the assemblies are versioned like this:
<table>
<tr><th>&nbsp;</th> <th>Debug</th> <th>Release</th></tr>
<tr><th>SharpDevelop.exe</th><td>2.x.y.r</td><td>2.x.y.r</td></tr>
<tr><th>Libraries</th> <td>2.0.0.1</td><td>2.x.y.r</td></tr>
</table>
</p>
<h2>Publisher Policy</h2>
<p>
While the assembly versioning schema is not so important inside SharpDevelop,
it is important for 3rd party addins because the main libraries like ICSharpCode.Core
are strong-named.
Normally, an assembly compiled against a strong-named assembly can only be used
with exactly the version of the library it was compiled with.
</p>
<p>
This means if a 3rd-party addin was compiled against version 2.0.1.a, it cannot bind to
version 2.0.1.b or 2.0.2.c; even if it would run without problems.
Therefore, SharpDevelop.exe.config contains binding redirects for the strong-named libraries
that addins would want to reference.
</p>
<p>
The binding redirects always redirect from version 2.0.0.1 to the current version.
That means 3rd-party addins must be compiled against a debug version of SharpDevelop (after
executing "resetAssemblyInfo.bat") and they will bind to every SharpDevelop version (and if the classes
used by the addin stayed binary compatible, it will even run with every SharpDevelop version).
</p>
</body>
</html>

4
src/AddIns/Misc/StartPage/Project/StartPage.addin

@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
<Path name = "/SharpDevelop/Workbench/MainMenu/View">
<MenuItem id = "ShowStartPage"
insertafter = "ViewItemsSeparator"
insertbefore = "StartPageSeparator"
insertbefore = "StartPageSeparator"
label = "${res:XML.MainMenu.ViewMenu.ShowStartPage}"
class = "ICSharpCode.StartPage.ShowStartPageCommand"/>
<MenuItem id = "StartPageSeparator"
@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
</Path>
<!-- TODO: Conditional to reflect Settings option -->
<Path name = "/Workspace/Autostart">
<Path name = "/Workspace/AutostartNothingLoaded">
<Class id = "ShowStartPageCommand"
class = "ICSharpCode.StartPage.ShowStartPageCommand"/>
</Path>

53
src/Main/Base/Project/Src/Commands/AutostartCommands.cs

@ -31,25 +31,18 @@ namespace ICSharpCode.SharpDevelop.Commands @@ -31,25 +31,18 @@ namespace ICSharpCode.SharpDevelop.Commands
}
}
public class StartWorkbenchCommand : AbstractCommand
public class StartWorkbenchCommand // : AbstractCommand
{
const string workbenchMemento = "WorkbenchMemento";
EventHandler idleEventHandler;
bool isCalled = false;
/// <remarks>
/// The worst workaround in the whole project
/// </remarks>
void ShowTipOfTheDay(object sender, EventArgs e)
{
if (isCalled) {
Application.Idle -= idleEventHandler;
return;
}
isCalled = true;
// show tip of the day
Application.Idle -= ShowTipOfTheDay;
// show tip of the day
if (PropertyService.Get("ShowTipsAtStartup", true)) {
ViewTipOfTheDay dview = new ViewTipOfTheDay();
dview.Run();
@ -110,49 +103,51 @@ namespace ICSharpCode.SharpDevelop.Commands @@ -110,49 +103,51 @@ namespace ICSharpCode.SharpDevelop.Commands
return false;
}
}
public override void Run()
public void Run(string[] fileList)
{
Form f = (Form)WorkbenchSingleton.Workbench;
f.Show();
idleEventHandler = new EventHandler(ShowTipOfTheDay);
Application.Idle += idleEventHandler;
Application.Idle += ShowTipOfTheDay;
/*
bool didLoadCombineOrFile = false;
foreach (string file in SplashScreenForm.GetRequestedFileList()) {
foreach (string file in fileList) {
didLoadCombineOrFile = true;
switch (System.IO.Path.GetExtension(file).ToUpper()) {
switch (Path.GetExtension(file).ToUpper()) {
case ".CMBX":
case ".PRJX":
case ".SLN":
case ".CSPROJ":
case ".VBPROJ":
FileUtility.ObservedLoad(new NamedFileOperationDelegate(ProjectService.LoadSolution), file);
break;
default:
try {
FileService.OpenFile(file);
} catch (Exception e) {
Console.WriteLine("unable to open file {0} exception was :\n{1}", file, e.ToString());
MessageService.ShowError(e, "unable to open file " + file);
}
break;
}
}
*/
// !didLoadCombineOrFile &&
// load previous combine
if ((bool)PropertyService.Get("SharpDevelop.LoadPrevProjectOnStartup", false)) {
object recentOpenObj = PropertyService.Get("ICSharpCode.SharpDevelop.Gui.MainWindow.RecentOpen");
if (recentOpenObj is ICSharpCode.Core.RecentOpen) {
ICSharpCode.Core.RecentOpen recOpen = (ICSharpCode.Core.RecentOpen)recentOpenObj;
if (recOpen.RecentProject.Count > 0) {
ProjectService.LoadSolution(recOpen.RecentProject[0].ToString());
}
if (!didLoadCombineOrFile && PropertyService.Get("SharpDevelop.LoadPrevProjectOnStartup", false)) {
if (FileService.RecentOpen.RecentProject.Count > 0) {
ProjectService.LoadSolution(FileService.RecentOpen.RecentProject[0].ToString());
didLoadCombineOrFile = true;
}
}
if (!didLoadCombineOrFile) {
foreach (ICommand command in AddInTree.BuildItems("/Workspace/AutostartNothingLoaded", null, false)) {
command.Run();
}
}
f.Focus(); // windows.forms focus workaround
f.Focus(); // windows.forms focus workaround
ParserService.StartParserThread();
@ -166,7 +161,7 @@ namespace ICSharpCode.SharpDevelop.Commands @@ -166,7 +161,7 @@ namespace ICSharpCode.SharpDevelop.Commands
try {
PropertyService.Set(workbenchMemento, WorkbenchSingleton.Workbench.CreateMemento());
} catch (Exception e) {
Console.WriteLine("Exception while saving workbench state: " + e.ToString());
MessageService.ShowError(e, "Exception while saving workbench state.");
}
}
}

8
src/Main/Base/Project/Src/Commands/FileMenuCommands.cs

@ -44,9 +44,13 @@ namespace ICSharpCode.SharpDevelop.Project.Commands @@ -44,9 +44,13 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
case ".SLN":
ProjectService.LoadSolution(fdiag.FileName);
break;
case ".CSPROJ":
case ".VBPROJ":
ProjectService.LoadProject(fdiag.FileName);
break;
// case ".PRJX":
//
//
//
//
// FileUtility.ObservedLoad(new NamedFileOperationDelegate(ProjectService.OpenSolution), fdiag.FileName);
// break;
default:

3
src/Main/Base/Project/Src/Gui/IWorkbenchLayout.cs

@ -18,9 +18,6 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -18,9 +18,6 @@ namespace ICSharpCode.SharpDevelop.Gui
/// </summary>
public interface IWorkbenchLayout
{
/// <summary>
/// The active workbench window.
/// </summary>
IWorkbenchWindow ActiveWorkbenchwindow {
get;
}

8
src/Main/Base/Project/Src/Gui/Workbench/DefaultWorkbench.cs

@ -359,11 +359,11 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -359,11 +359,11 @@ namespace ICSharpCode.SharpDevelop.Gui
// protected void OnTopMenuSelected(MenuCommand mc)
// {
//
//
//
//
// StatusBarService.SetMessage(mc.Description);
// }
//
//
// protected void OnTopMenuDeselected(MenuCommand mc)
// {
// SetStandardStatusBar(null, null);
@ -428,7 +428,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -428,7 +428,7 @@ namespace ICSharpCode.SharpDevelop.Gui
if (pad.Class == type.FullName) {
return pad;
}
}
}
return null;
}
void CreateMainMenu()

14
src/Main/Base/Project/Src/Services/File/RecentOpen.cs

@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
using System;
using System.Xml;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.IO;
@ -29,20 +29,20 @@ namespace ICSharpCode.Core @@ -29,20 +29,20 @@ namespace ICSharpCode.Core
/// </summary>
int MAX_LENGTH = 10;
ArrayList lastfile = new ArrayList();
ArrayList lastproject = new ArrayList();
List<string> lastfile = new List<string>();
List<string> lastproject = new List<string>();
public event EventHandler RecentFileChanged;
public event EventHandler RecentProjectChanged;
public ArrayList RecentFile {
public List<string> RecentFile {
get {
System.Diagnostics.Debug.Assert(lastfile != null, "RecentOpen : set string[] LastFile (value == null)");
return lastfile;
}
}
public ArrayList RecentProject {
public List<string> RecentProject {
get {
System.Diagnostics.Debug.Assert(lastproject != null, "RecentOpen : set string[] LastProject (value == null)");
return lastproject;
@ -151,8 +151,8 @@ namespace ICSharpCode.Core @@ -151,8 +151,8 @@ namespace ICSharpCode.Core
public Properties ToProperties()
{
Properties p = new Properties();
p["Files"] = String.Join(",", (string[])lastfile.ToArray(typeof(string)));
p["Projects"] = String.Join(",", (string[])lastproject.ToArray(typeof(string)));
p["Files"] = String.Join(",", lastfile.ToArray());
p["Projects"] = String.Join(",", lastproject.ToArray());
return p;
}

20
src/Main/Base/Project/Src/Services/ParserService/ParserService.cs

@ -204,15 +204,27 @@ namespace ICSharpCode.Core @@ -204,15 +204,27 @@ namespace ICSharpCode.Core
}
}
static object[] GetWorkbench()
{
IWorkbenchWindow activeWorkbenchWindow = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow;
if (activeWorkbenchWindow == null)
return null;
IBaseViewContent activeViewContent = activeWorkbenchWindow.ActiveViewContent;
if (activeViewContent == null)
return null;
return new object[] { activeViewContent, activeWorkbenchWindow.ViewContent };
}
static void ParserUpdateStep()
{
if (WorkbenchSingleton.Workbench.ActiveWorkbenchWindow != null && WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent != null) {
IEditable editable = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as IEditable;
object[] workbench = (object[])WorkbenchSingleton.SafeThreadCall(typeof(ParserService), "GetWorkbench");
if (workbench != null) {
IEditable editable = workbench[0] as IEditable;
if (editable != null) {
string fileName = null;
IViewContent viewContent = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ViewContent;
IParseableContent parseableContent = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as IParseableContent;
IViewContent viewContent = (IViewContent)workbench[1];
IParseableContent parseableContent = workbench[0] as IParseableContent;
//ivoko: Pls, do not throw text = parseableContent.ParseableText away. I NEED it.
string text = null;

28
src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs

@ -180,19 +180,29 @@ namespace ICSharpCode.SharpDevelop.Project @@ -180,19 +180,29 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
public static void LoadProject(string fileName)
{
openSolution = new Solution();
openSolution.Name = Path.GetFileNameWithoutExtension(fileName);
openSolution.Save(Path.ChangeExtension(fileName, ".sln"));
OnSolutionLoaded(new SolutionEventArgs(openSolution));
string solutionFile = Path.ChangeExtension(fileName, ".sln");
if (File.Exists(solutionFile)) {
LoadSolution(solutionFile);
return;
}
Solution solution = new Solution();
solution.Name = Path.GetFileNameWithoutExtension(fileName);
ILanguageBinding binding = LanguageBindingService.GetBindingPerProjectFile(fileName);
IProject newProject;
IProject project;
if (binding != null) {
newProject = binding.LoadProject(fileName, openSolution.Name);
project = binding.LoadProject(fileName, solution.Name);
} else {
newProject = new UnknownProject(fileName);
MessageService.ShowError(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Commands.OpenCombine.InvalidProjectOrCombine}", new string[,] {{"FileName", fileName}}));
return;
}
solution.AddFolder(project);
solution.Save(solutionFile);
openSolution = solution;
OnSolutionLoaded(new SolutionEventArgs(openSolution));
string file = GetPreferenceFileName(project);
if (FileUtility.IsValidFileName(file) && File.Exists(file)) {
project.SetMemento(Properties.Load(file));
}
newProject.IdGuid = Guid.NewGuid().ToString();
openSolution.AddFolder(newProject);
}
public static void SaveSolution()

12
src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CodeCompletionDataUsageCache.cs

@ -48,8 +48,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -48,8 +48,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
/// the file. Items with less uses than this count also get a priority penalty.
/// (Because the first use would otherwise always be 100% priority)</summary>
const int MinUsesForSave = 2;
/// <summary>Minimum percentage (Uses * 100 / ShowCount) an item must have to be saved.</summary>
const int MinPercentageForSave = 1;
public static string CacheFilename {
get {
@ -78,6 +76,12 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -78,6 +76,12 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
string key = reader.ReadString();
int uses = reader.ReadInt32();
int showCount = reader.ReadInt32();
if (showCount > 1000) {
// reduce count because the usage in the next time
// should have more influence on the past
showCount /= 3;
uses /= 3;
}
dict.Add(key, new UsageStruct(uses, showCount));
}
}
@ -115,9 +119,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -115,9 +119,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
} else {
List<KeyValuePair<string, UsageStruct>> saveItems = new List<KeyValuePair<string, UsageStruct>>();
foreach (KeyValuePair<string, UsageStruct> entry in dict) {
if (entry.Value.Uses > MinUsesForSave &&
entry.Value.Uses * 100 / entry.Value.ShowCount >= MinPercentageForSave)
{
if (entry.Value.Uses > MinUsesForSave) {
saveItems.Add(entry);
}
}

42
src/Main/Core/Project/Src/AddInTree/AddInTree.cs

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
using System;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
namespace ICSharpCode.Core
@ -84,6 +85,11 @@ namespace ICSharpCode.Core @@ -84,6 +85,11 @@ namespace ICSharpCode.Core
}
public static AddInTreeNode GetTreeNode(string path)
{
return GetTreeNode(path, true);
}
public static AddInTreeNode GetTreeNode(string path, bool throwOnNotFound)
{
if (path == null || path.Length == 0) {
return rootNode;
@ -93,7 +99,10 @@ namespace ICSharpCode.Core @@ -93,7 +99,10 @@ namespace ICSharpCode.Core
int i = 0;
while (i < splittedPath.Length) {
if (!curPath.ChildNodes.ContainsKey(splittedPath[i])) {
throw new TreePathNotFoundException(path);
if (throwOnNotFound)
throw new TreePathNotFoundException(path);
else
return null;
}
curPath = curPath.ChildNodes[splittedPath[i]];
++i;
@ -113,6 +122,23 @@ namespace ICSharpCode.Core @@ -113,6 +122,23 @@ namespace ICSharpCode.Core
return node.BuildChildItem(child, caller);
}
/// <summary>
/// Builds the items in the path.
/// </summary>
/// <param name="path">A path in the addin tree.</param>
/// <param name="caller">The owner used to create the objects.</param>
/// <param name="throwOnNotFound">If true, throws an TreePathNotFoundException
/// if the path is not found. If false, an empty ArrayList is returned when the
/// path is not found.</param>
public static ArrayList BuildItems(string path, object caller, bool throwOnNotFound)
{
AddInTreeNode node = GetTreeNode(path, throwOnNotFound);
if (node == null)
return new ArrayList();
else
return node.BuildChildItems(caller);
}
static AddInTreeNode CreatePath(AddInTreeNode localRoot, string path)
{
if (path == null || path.Length == 0) {
@ -139,7 +165,7 @@ namespace ICSharpCode.Core @@ -139,7 +165,7 @@ namespace ICSharpCode.Core
treePath.Codons.Add(codon);
}
}
static void InsertAddIn(AddIn addIn)
{
foreach (ExtensionPath path in addIn.Paths.Values) {
@ -148,16 +174,16 @@ namespace ICSharpCode.Core @@ -148,16 +174,16 @@ namespace ICSharpCode.Core
addIns.Add(addIn);
}
// As long as the show form takes 10 times of loading the xml representation I'm not implementing
// binary serialization.
// As long as the show form takes 10 times of loading the xml representation I'm not implementing
// binary serialization.
// static Dictionary<string, ushort> nameLookupTable = new Dictionary<string, ushort>();
// static Dictionary<AddIn, ushort> addInLookupTable = new Dictionary<AddIn, ushort>();
//
//
// public static ushort GetAddInOffset(AddIn addIn)
// {
// return addInLookupTable[addIn];
// }
//
//
// public static ushort GetNameOffset(string name)
// {
// if (!nameLookupTable.ContainsKey(name)) {
@ -165,7 +191,7 @@ namespace ICSharpCode.Core @@ -165,7 +191,7 @@ namespace ICSharpCode.Core
// }
// return nameLookupTable[name];
// }
//
//
// public static void BinarySerialize(string fileName)
// {
// for (int i = 0; i < addIns.Count; ++i) {
@ -189,6 +215,6 @@ namespace ICSharpCode.Core @@ -189,6 +215,6 @@ namespace ICSharpCode.Core
foreach (string fileName in addInFiles) {
InsertAddIn(AddIn.Load(fileName));
}
}
}
}
}

12
src/Main/StartUp/Project/SharpDevelopMain.cs

@ -20,6 +20,7 @@ using System.Runtime.Remoting; @@ -20,6 +20,7 @@ using System.Runtime.Remoting;
using System.Security.Policy;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Commands;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
@ -168,22 +169,19 @@ namespace ICSharpCode.SharpDevelop @@ -168,22 +169,19 @@ namespace ICSharpCode.SharpDevelop
PropertyService.Load();
StringParser.RegisterStringTagProvider(new ICSharpCode.SharpDevelop.Commands.SharpDevelopStringTagProvider());
StringParser.RegisterStringTagProvider(new SharpDevelopStringTagProvider());
AddInTree.Load();
// .NET base autostarts
// taken out of the add-in tree for performance reasons (every tick in startup counts)
new ICSharpCode.SharpDevelop.Commands.InitializeWorkbenchCommand().Run();
new InitializeWorkbenchCommand().Run();
// run workspace autostart commands
try {
ArrayList commands = AddInTree.GetTreeNode("/Workspace/Autostart").BuildChildItems(null);
foreach (ICommand command in commands) {
foreach (ICommand command in AddInTree.BuildItems("/Workspace/Autostart", null, false)) {
command.Run();
}
} catch (TreePathNotFoundException) {
// Do nothing.
} catch (XmlException e) {
MessageBox.Show("Could not load XML :" + Environment.NewLine + e.Message);
return;
@ -198,7 +196,7 @@ namespace ICSharpCode.SharpDevelop @@ -198,7 +196,7 @@ namespace ICSharpCode.SharpDevelop
// finally start the workbench.
try {
new ICSharpCode.SharpDevelop.Commands.StartWorkbenchCommand().Run();
new StartWorkbenchCommand().Run(SplashScreenForm.GetRequestedFileList());
} finally {
// unloading
ProjectService.CloseSolution();

Loading…
Cancel
Save