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 21 years ago
parent
commit
8545cf82a6
  1. 62
      doc/technotes/Versioning.html
  2. 2
      src/AddIns/Misc/StartPage/Project/StartPage.addin
  3. 49
      src/Main/Base/Project/Src/Commands/AutostartCommands.cs
  4. 4
      src/Main/Base/Project/Src/Commands/FileMenuCommands.cs
  5. 3
      src/Main/Base/Project/Src/Gui/IWorkbenchLayout.cs
  6. 14
      src/Main/Base/Project/Src/Services/File/RecentOpen.cs
  7. 20
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
  8. 28
      src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs
  9. 12
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CodeCompletionDataUsageCache.cs
  10. 30
      src/Main/Core/Project/Src/AddInTree/AddInTree.cs
  11. 12
      src/Main/StartUp/Project/SharpDevelopMain.cs

62
doc/technotes/Versioning.html

@ -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>

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

@ -21,7 +21,7 @@
</Path> </Path>
<!-- TODO: Conditional to reflect Settings option --> <!-- TODO: Conditional to reflect Settings option -->
<Path name = "/Workspace/Autostart"> <Path name = "/Workspace/AutostartNothingLoaded">
<Class id = "ShowStartPageCommand" <Class id = "ShowStartPageCommand"
class = "ICSharpCode.StartPage.ShowStartPageCommand"/> class = "ICSharpCode.StartPage.ShowStartPageCommand"/>
</Path> </Path>

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

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

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

@ -44,6 +44,10 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
case ".SLN": case ".SLN":
ProjectService.LoadSolution(fdiag.FileName); ProjectService.LoadSolution(fdiag.FileName);
break; break;
case ".CSPROJ":
case ".VBPROJ":
ProjectService.LoadProject(fdiag.FileName);
break;
// case ".PRJX": // case ".PRJX":
// //
// //

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

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

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

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

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

@ -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() static void ParserUpdateStep()
{ {
if (WorkbenchSingleton.Workbench.ActiveWorkbenchWindow != null && WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent != null) { object[] workbench = (object[])WorkbenchSingleton.SafeThreadCall(typeof(ParserService), "GetWorkbench");
IEditable editable = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as IEditable; if (workbench != null) {
IEditable editable = workbench[0] as IEditable;
if (editable != null) { if (editable != null) {
string fileName = null; string fileName = null;
IViewContent viewContent = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ViewContent; IViewContent viewContent = (IViewContent)workbench[1];
IParseableContent parseableContent = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as IParseableContent; IParseableContent parseableContent = workbench[0] as IParseableContent;
//ivoko: Pls, do not throw text = parseableContent.ParseableText away. I NEED it. //ivoko: Pls, do not throw text = parseableContent.ParseableText away. I NEED it.
string text = null; string text = null;

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

@ -180,19 +180,29 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary> /// </summary>
public static void LoadProject(string fileName) public static void LoadProject(string fileName)
{ {
openSolution = new Solution(); string solutionFile = Path.ChangeExtension(fileName, ".sln");
openSolution.Name = Path.GetFileNameWithoutExtension(fileName); if (File.Exists(solutionFile)) {
openSolution.Save(Path.ChangeExtension(fileName, ".sln")); LoadSolution(solutionFile);
OnSolutionLoaded(new SolutionEventArgs(openSolution)); return;
}
Solution solution = new Solution();
solution.Name = Path.GetFileNameWithoutExtension(fileName);
ILanguageBinding binding = LanguageBindingService.GetBindingPerProjectFile(fileName); ILanguageBinding binding = LanguageBindingService.GetBindingPerProjectFile(fileName);
IProject newProject; IProject project;
if (binding != null) { if (binding != null) {
newProject = binding.LoadProject(fileName, openSolution.Name); project = binding.LoadProject(fileName, solution.Name);
} else { } 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() 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
/// the file. Items with less uses than this count also get a priority penalty. /// 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> /// (Because the first use would otherwise always be 100% priority)</summary>
const int MinUsesForSave = 2; 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 { public static string CacheFilename {
get { get {
@ -78,6 +76,12 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
string key = reader.ReadString(); string key = reader.ReadString();
int uses = reader.ReadInt32(); int uses = reader.ReadInt32();
int showCount = 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)); dict.Add(key, new UsageStruct(uses, showCount));
} }
} }
@ -115,9 +119,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
} else { } else {
List<KeyValuePair<string, UsageStruct>> saveItems = new List<KeyValuePair<string, UsageStruct>>(); List<KeyValuePair<string, UsageStruct>> saveItems = new List<KeyValuePair<string, UsageStruct>>();
foreach (KeyValuePair<string, UsageStruct> entry in dict) { foreach (KeyValuePair<string, UsageStruct> entry in dict) {
if (entry.Value.Uses > MinUsesForSave && if (entry.Value.Uses > MinUsesForSave) {
entry.Value.Uses * 100 / entry.Value.ShowCount >= MinPercentageForSave)
{
saveItems.Add(entry); saveItems.Add(entry);
} }
} }

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

@ -8,6 +8,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
namespace ICSharpCode.Core namespace ICSharpCode.Core
@ -84,6 +85,11 @@ namespace ICSharpCode.Core
} }
public static AddInTreeNode GetTreeNode(string path) public static AddInTreeNode GetTreeNode(string path)
{
return GetTreeNode(path, true);
}
public static AddInTreeNode GetTreeNode(string path, bool throwOnNotFound)
{ {
if (path == null || path.Length == 0) { if (path == null || path.Length == 0) {
return rootNode; return rootNode;
@ -93,7 +99,10 @@ namespace ICSharpCode.Core
int i = 0; int i = 0;
while (i < splittedPath.Length) { while (i < splittedPath.Length) {
if (!curPath.ChildNodes.ContainsKey(splittedPath[i])) { if (!curPath.ChildNodes.ContainsKey(splittedPath[i])) {
if (throwOnNotFound)
throw new TreePathNotFoundException(path); throw new TreePathNotFoundException(path);
else
return null;
} }
curPath = curPath.ChildNodes[splittedPath[i]]; curPath = curPath.ChildNodes[splittedPath[i]];
++i; ++i;
@ -113,6 +122,23 @@ namespace ICSharpCode.Core
return node.BuildChildItem(child, caller); 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) static AddInTreeNode CreatePath(AddInTreeNode localRoot, string path)
{ {
if (path == null || path.Length == 0) { if (path == null || path.Length == 0) {
@ -148,8 +174,8 @@ namespace ICSharpCode.Core
addIns.Add(addIn); addIns.Add(addIn);
} }
// As long as the show form takes 10 times of loading the xml representation I'm not implementing // As long as the show form takes 10 times of loading the xml representation I'm not implementing
// binary serialization. // binary serialization.
// static Dictionary<string, ushort> nameLookupTable = new Dictionary<string, ushort>(); // static Dictionary<string, ushort> nameLookupTable = new Dictionary<string, ushort>();
// static Dictionary<AddIn, ushort> addInLookupTable = new Dictionary<AddIn, ushort>(); // static Dictionary<AddIn, ushort> addInLookupTable = new Dictionary<AddIn, ushort>();
// //

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

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

Loading…
Cancel
Save