1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
5
using System.Collections.Generic;
8
using ICSharpCode.Core;
9
using ICSharpCode.SharpDevelop.Project;
11
namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
14
/// Tracks the names of the top-used CodeCompletionData items and gives them higher
15
/// priority in the completion dropdown.
17
public static class CodeCompletionDataUsageCache
22
public UsageStruct(int Uses, int ShowCount) {
24
this.ShowCount = ShowCount;
28
static Dictionary<string, UsageStruct> dict;
30
// File format for stored CodeCompletionDataUsageCache
31
// long magic = 0x6567617355444343 (identifies file type = 'CCDUsage')
32
// short version = 1 (file version)
40
const long magic = 0x6567617355444343;
41
const short version = 1;
43
/// <summary>Minimum number how often an item must be used to be saved to
44
/// the file. Items with less uses than this count also get a priority penalty.
45
/// (Because the first use would otherwise always be 100% priority)</summary>
46
const int MinUsesForSave = 2;
48
public static string CacheFilename {
50
if (string.IsNullOrEmpty(PropertyService.ConfigDirectory))
53
return Path.Combine(PropertyService.ConfigDirectory, "CodeCompletionUsageCache.dat");
57
static void LoadCache()
59
dict = new Dictionary<string, UsageStruct>();
60
ProjectService.SolutionClosed += delegate(object sender, EventArgs e) { SaveCache(); };
61
string cacheFileName = CodeCompletionDataUsageCache.CacheFilename;
62
if (string.IsNullOrEmpty(cacheFileName) || !File.Exists(cacheFileName))
64
using (FileStream fs = new FileStream(cacheFileName, FileMode.Open, FileAccess.Read)) {
65
using (BinaryReader reader = new BinaryReader(fs)) {
66
if (reader.ReadInt64() != magic) {
67
LoggingService.Warn("CodeCompletionDataUsageCache: wrong file magic");
70
if (reader.ReadInt16() != version) {
71
LoggingService.Warn("CodeCompletionDataUsageCache: unknown file version");
74
int itemCount = reader.ReadInt32();
75
for (int i = 0; i < itemCount; i++) {
76
string key = reader.ReadString();
77
int uses = reader.ReadInt32();
78
int showCount = reader.ReadInt32();
79
if (showCount > 1000) {
80
// reduce count because the usage in the next time
81
// should have more influence on the past
85
dict.Add(key, new UsageStruct(uses, showCount));
89
LoggingService.Info("Loaded CodeCompletionDataUsageCache (" + dict.Count + " items)");
92
public static void SaveCache()
94
string cacheFileName = CodeCompletionDataUsageCache.CacheFilename;
95
if (dict == null || string.IsNullOrEmpty(cacheFileName)) {
99
using (FileStream fs = new FileStream(cacheFileName, FileMode.Create, FileAccess.Write)) {
100
using (BinaryWriter writer = new BinaryWriter(fs)) {
101
count = SaveCache(writer);
104
LoggingService.Info("Saved CodeCompletionDataUsageCache (" + count + " of " + dict.Count + " items)");
107
static int SaveCache(BinaryWriter writer)
110
writer.Write(version);
111
int maxSaveItems = CodeCompletionOptions.DataUsageCacheItemCount;
112
if (dict.Count < maxSaveItems) {
113
writer.Write(dict.Count);
114
foreach (KeyValuePair<string, UsageStruct> entry in dict) {
115
writer.Write(entry.Key);
116
writer.Write(entry.Value.Uses);
117
writer.Write(entry.Value.ShowCount);
121
List<KeyValuePair<string, UsageStruct>> saveItems = new List<KeyValuePair<string, UsageStruct>>();
122
foreach (KeyValuePair<string, UsageStruct> entry in dict) {
123
if (entry.Value.Uses > MinUsesForSave) {
124
saveItems.Add(entry);
127
if (saveItems.Count > maxSaveItems) {
128
saveItems.Sort(new SaveItemsComparer());
130
int count = Math.Min(maxSaveItems, saveItems.Count);
132
for (int i = 0; i < count; i++) {
133
KeyValuePair<string, UsageStruct> entry = saveItems[i];
134
writer.Write(entry.Key);
135
writer.Write(entry.Value.Uses);
136
writer.Write(entry.Value.ShowCount);
142
class SaveItemsComparer : IComparer<KeyValuePair<string, UsageStruct>>
144
public int Compare(KeyValuePair<string, UsageStruct> x, KeyValuePair<string, UsageStruct> y)
146
double a = ((double)x.Value.Uses / x.Value.ShowCount);
147
return -a.CompareTo((double)y.Value.Uses / y.Value.ShowCount);
151
public static void ResetCache()
153
dict = new Dictionary<string, UsageStruct>();
155
if (File.Exists(CacheFilename)) {
156
File.Delete(CacheFilename);
158
} catch (Exception ex) {
159
LoggingService.Warn("CodeCompletionDataUsageCache.ResetCache(): " + ex.Message);
163
public static double GetPriority(string dotnetName, bool incrementShowCount)
165
if (!CodeCompletionOptions.DataUsageCacheEnabled)
171
if (!dict.TryGetValue(dotnetName, out usage))
173
double priority = (double)usage.Uses / usage.ShowCount;
174
if (usage.Uses < MinUsesForSave)
176
if (incrementShowCount) {
177
usage.ShowCount += 1;
178
dict[dotnetName] = usage;
183
public static void IncrementUsage(string dotnetName)
185
if (!CodeCompletionOptions.DataUsageCacheEnabled)
191
if (!dict.TryGetValue(dotnetName, out usage)) {
192
usage = new UsageStruct(0, 2);
195
dict[dotnetName] = usage;