From 07501c2c6484d2a2d836da8f4639a3a5abbe554a Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Mon, 20 Nov 2017 10:11:49 +0100 Subject: [PATCH] Remove BoundedMap --- .../ui/resourceviewer/resourceViewer.ts | 4 +- src/vs/base/common/filters.ts | 4 +- src/vs/base/common/glob.ts | 4 +- src/vs/base/common/map.ts | 190 +---------- src/vs/base/common/strings.ts | 8 +- src/vs/base/test/common/map.test.ts | 321 +----------------- .../quickopen/browser/commandsHandler.ts | 50 +-- 7 files changed, 63 insertions(+), 518 deletions(-) diff --git a/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts b/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts index 2404e3700f9..543e921c680 100644 --- a/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts +++ b/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts @@ -13,7 +13,7 @@ import paths = require('vs/base/common/paths'); import { Builder, $ } from 'vs/base/browser/builder'; import DOM = require('vs/base/browser/dom'); import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; -import { BoundedMap } from 'vs/base/common/map'; +import { LRUCache } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; interface MapExtToMediaMimes { @@ -82,7 +82,7 @@ export interface IResourceDescriptor { // we need to bypass the cache or not. We could always bypass the cache everytime we show the image // however that has very bad impact on memory consumption because each time the image gets shown, // memory grows (see also https://github.com/electron/electron/issues/6275) -const IMAGE_RESOURCE_ETAG_CACHE = new BoundedMap<{ etag: string, src: string }>(100); +const IMAGE_RESOURCE_ETAG_CACHE = new LRUCache(100); function imageSrc(descriptor: IResourceDescriptor): string { if (descriptor.resource.scheme === Schemas.data) { return descriptor.resource.toString(true /* skip encoding */); diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index d9fe889ca1d..b43808d4e31 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -5,7 +5,7 @@ 'use strict'; import strings = require('vs/base/common/strings'); -import { BoundedMap } from 'vs/base/common/map'; +import { LRUCache } from 'vs/base/common/map'; import { CharCode } from 'vs/base/common/charCode'; export interface IFilter { @@ -317,7 +317,7 @@ function nextWord(word: string, start: number): number { export const fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString); const fuzzySeparateFilter = or(matchesPrefix, matchesCamelCase, matchesSubString); -const fuzzyRegExpCache = new BoundedMap(10000); // bounded to 10000 elements +const fuzzyRegExpCache = new LRUCache(10000); // bounded to 10000 elements export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSeparateSubstringMatching = false): IMatch[] { if (typeof word !== 'string' || typeof wordToMatchAgainst !== 'string') { diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index d051daf96bc..17aa34c5399 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -7,7 +7,7 @@ import arrays = require('vs/base/common/arrays'); import strings = require('vs/base/common/strings'); import paths = require('vs/base/common/paths'); -import { BoundedMap } from 'vs/base/common/map'; +import { LRUCache } from 'vs/base/common/map'; import { CharCode } from 'vs/base/common/charCode'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -267,7 +267,7 @@ interface ParsedExpressionPattern { allPaths?: string[]; } -const CACHE = new BoundedMap(10000); // bounded to 10000 elements +const CACHE = new LRUCache(10000); // bounded to 10000 elements const FALSE = function () { return false; diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 20afbbf6bb9..e5b413dde70 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -7,11 +7,6 @@ import URI from 'vs/base/common/uri'; -export interface Entry { - key: K; - value: T; -} - export function values(map: Map): V[] { const result: V[] = []; map.forEach(value => result.push(value)); @@ -36,187 +31,6 @@ export function getOrSet(map: Map, key: K, value: V): V { return result; } -export interface ISerializedBoundedLinkedMap { - version?: string; - entries: { key: string; value: T }[]; -} - -interface LinkedEntry extends Entry { - next?: LinkedEntry; - prev?: LinkedEntry; -} - -/** - * A simple Map that optionally allows to set a limit of entries to store. Once the limit is hit, - * the cache will remove the entry that was last recently added. Or, if a ratio is provided below 1, - * all elements will be removed until the ratio is full filled (e.g. 0.75 to remove 25% of old elements). - */ -export class BoundedMap { - private map: Map>; - - private head: LinkedEntry; - private tail: LinkedEntry; - private ratio: number; - - constructor(private limit = Number.MAX_VALUE, ratio = 1, value?: ISerializedBoundedLinkedMap) { - this.map = new Map>(); - this.ratio = limit * ratio; - - if (value) { - value.entries.forEach(entry => { - this.set(entry.key, entry.value); - }); - } - } - - public setLimit(limit: number): void { - if (limit < 0) { - return; // invalid limit - } - - this.limit = limit; - while (this.map.size > this.limit) { - this.trim(); - } - } - - public serialize(): ISerializedBoundedLinkedMap { - const serialized: ISerializedBoundedLinkedMap = { entries: [] }; - - this.map.forEach(entry => { - serialized.entries.push({ key: entry.key, value: entry.value }); - }); - - return serialized; - } - - public get size(): number { - return this.map.size; - } - - public set(key: string, value: T): boolean { - if (this.map.has(key)) { - return false; // already present! - } - - const entry: LinkedEntry = { key, value }; - this.push(entry); - - if (this.size > this.limit) { - this.trim(); - } - - return true; - } - - public get(key: string): T { - const entry = this.map.get(key); - - return entry ? entry.value : null; - } - - public getOrSet(k: string, t: T): T { - const res = this.get(k); - if (res) { - return res; - } - - this.set(k, t); - - return t; - } - - public delete(key: string): T { - const entry = this.map.get(key); - - if (entry) { - this.map.delete(key); - - if (entry.next) { - entry.next.prev = entry.prev; // [A]<-[x]<-[C] = [A]<-[C] - } else { - this.head = entry.prev; // [A]-[x] = [A] - } - - if (entry.prev) { - entry.prev.next = entry.next; // [A]->[x]->[C] = [A]->[C] - } else { - this.tail = entry.next; // [x]-[A] = [A] - } - - return entry.value; - } - - return null; - } - - public has(key: string): boolean { - return this.map.has(key); - } - - public clear(): void { - this.map.clear(); - this.head = null; - this.tail = null; - } - - private push(entry: LinkedEntry): void { - if (this.head) { - // [A]-[B] = [A]-[B]->[X] - entry.prev = this.head; - this.head.next = entry; - } - - if (!this.tail) { - this.tail = entry; - } - - this.head = entry; - - this.map.set(entry.key, entry); - } - - private trim(): void { - if (this.tail) { - - // Remove all elements until ratio is reached - if (this.ratio < this.limit) { - let index = 0; - let current = this.tail; - while (current.next) { - - // Remove the entry - this.map.delete(current.key); - - // if we reached the element that overflows our ratio condition - // make its next element the new tail of the Map and adjust the size - if (index === this.ratio) { - this.tail = current.next; - this.tail.prev = null; - - break; - } - - // Move on - current = current.next; - index++; - } - } - - // Just remove the tail element - else { - this.map.delete(this.tail.key); - - // [x]-[B] = [B] - this.tail = this.tail.next; - if (this.tail) { - this.tail.prev = null; - } - } - } - } -} - export interface IKeyIterator { reset(key: string): this; next(): this; @@ -975,6 +789,10 @@ export class LRUCache extends LinkedMap { return super.get(key, Touch.AsNew); } + public peek(key: K): V | undefined { + return super.get(key, Touch.None); + } + public set(key: K, value: V): void { super.set(key, value, Touch.AsNew); this.checkTrim(); diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 536eabdbbea..6f979c4c459 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { BoundedMap } from 'vs/base/common/map'; +import { LRUCache } from 'vs/base/common/map'; import { CharCode } from 'vs/base/common/charCode'; /** @@ -243,18 +243,18 @@ export function regExpContainsBackreference(regexpValue: string): boolean { */ export const canNormalize = typeof (('').normalize) === 'function'; -const nfcCache = new BoundedMap(10000); // bounded to 10000 elements +const nfcCache = new LRUCache(10000); // bounded to 10000 elements export function normalizeNFC(str: string): string { return normalize(str, 'NFC', nfcCache); } -const nfdCache = new BoundedMap(10000); // bounded to 10000 elements +const nfdCache = new LRUCache(10000); // bounded to 10000 elements export function normalizeNFD(str: string): string { return normalize(str, 'NFD', nfdCache); } const nonAsciiCharactersPattern = /[^\u0000-\u0080]/; -function normalize(str: string, form: string, normalizedCache: BoundedMap): string { +function normalize(str: string, form: string, normalizedCache: LRUCache): string { if (!canNormalize || !str) { return str; } diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index 627437ec6fc..11420c395e3 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -5,8 +5,7 @@ 'use strict'; - -import { BoundedMap, ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache } from 'vs/base/common/map'; +import { ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache } from 'vs/base/common/map'; import * as assert from 'assert'; import URI from 'vs/base/common/uri'; @@ -130,7 +129,7 @@ suite('Map', () => { assert.ok(!map.has('1')); }); - test('LinkedMap - LRUCache simple', () => { + test('LinkedMap - LRU Cache simple', () => { const cache = new LRUCache(5); [1, 2, 3, 4, 5].forEach(value => cache.set(value, value)); @@ -146,6 +145,21 @@ suite('Map', () => { assert.deepStrictEqual(values, [3, 4, 5, 6, 7]); }); + test('LinkedMap - LRU Cache get', () => { + const cache = new LRUCache(5); + + [1, 2, 3, 4, 5].forEach(value => cache.set(value, value)); + assert.strictEqual(cache.size, 5); + assert.deepStrictEqual(cache.keys(), [1, 2, 3, 4, 5]); + cache.get(3); + assert.deepStrictEqual(cache.keys(), [1, 2, 4, 5, 3]); + cache.peek(4); + assert.deepStrictEqual(cache.keys(), [1, 2, 4, 5, 3]); + let values: number[] = []; + [1, 2, 3, 4, 5].forEach(key => values.push(cache.get(key))); + assert.deepStrictEqual(values, [1, 2, 3, 4, 5]); + }); + test('LinkedMap - LRU Cache limit', () => { const cache = new LRUCache(10); @@ -170,7 +184,7 @@ suite('Map', () => { assert.deepStrictEqual(cache.values(), values); }); - test('LinkedMap - LRU Cache limit with ration', () => { + test('LinkedMap - LRU Cache limit with ratio', () => { const cache = new LRUCache(10, 0.5); for (let i = 1; i <= 10; i++) { @@ -186,305 +200,6 @@ suite('Map', () => { assert.deepStrictEqual(cache.values(), values); }); - test('BoundedMap - basics', function () { - const map = new BoundedMap(); - - assert.equal(map.size, 0); - - map.set('1', 1); - map.set('2', '2'); - map.set('3', true); - - const obj = Object.create(null); - map.set('4', obj); - - const date = Date.now(); - map.set('5', date); - - assert.equal(map.size, 5); - assert.equal(map.get('1'), 1); - assert.equal(map.get('2'), '2'); - assert.equal(map.get('3'), true); - assert.equal(map.get('4'), obj); - assert.equal(map.get('5'), date); - assert.ok(!map.get('6')); - - map.delete('6'); - assert.equal(map.size, 5); - assert.equal(map.delete('1'), 1); - assert.equal(map.delete('2'), '2'); - assert.equal(map.delete('3'), true); - assert.equal(map.delete('4'), obj); - assert.equal(map.delete('5'), date); - - assert.equal(map.size, 0); - assert.ok(!map.get('5')); - assert.ok(!map.get('4')); - assert.ok(!map.get('3')); - assert.ok(!map.get('2')); - assert.ok(!map.get('1')); - - map.set('1', 1); - map.set('2', '2'); - assert.ok(map.set('3', true)); // adding an element returns true - assert.ok(!map.set('3', true)); // adding it again returns false - - assert.ok(map.has('1')); - assert.equal(map.get('1'), 1); - assert.equal(map.get('2'), '2'); - assert.equal(map.get('3'), true); - - map.clear(); - - assert.equal(map.size, 0); - assert.ok(!map.get('1')); - assert.ok(!map.get('2')); - assert.ok(!map.get('3')); - assert.ok(!map.has('1')); - - const res = map.getOrSet('foo', 'bar'); - assert.equal(map.get('foo'), res); - assert.equal(res, 'bar'); - }); - - test('BoundedMap - serialization', function () { - const map = new BoundedMap(5); - - map.set('1', 1); - map.set('2', '2'); - map.set('3', true); - - const obj = Object.create(null); - map.set('4', obj); - - const date = Date.now(); - map.set('5', date); - - const mapClone = new BoundedMap(5, 1, map.serialize()); - - assert.deepEqual(map.serialize(), mapClone.serialize()); - - assert.equal(mapClone.size, 5); - assert.equal(mapClone.get('1'), 1); - assert.equal(mapClone.get('2'), '2'); - assert.equal(mapClone.get('3'), true); - assert.equal(mapClone.get('4'), obj); - assert.equal(mapClone.get('5'), date); - assert.ok(!mapClone.get('6')); - - mapClone.set('6', '6'); - assert.equal(mapClone.size, 5); - assert.ok(!mapClone.get('1')); - }); - - test('BoundedMap - setLimit', function () { - const map = new BoundedMap(5); - - map.set('1', 1); - map.set('2', '2'); - map.set('3', true); - - const obj = Object.create(null); - map.set('4', obj); - - const date = Date.now(); - map.set('5', date); - - assert.equal(map.size, 5); - assert.equal(map.get('1'), 1); - assert.equal(map.get('2'), '2'); - assert.equal(map.get('3'), true); - assert.equal(map.get('4'), obj); - assert.equal(map.get('5'), date); - assert.ok(!map.get('6')); - - map.setLimit(3); - - assert.equal(map.size, 3); - assert.ok(!map.get('1')); - assert.ok(!map.get('2')); - assert.equal(map.get('3'), true); - assert.equal(map.get('4'), obj); - assert.equal(map.get('5'), date); - - map.setLimit(0); - - assert.equal(map.size, 0); - assert.ok(!map.get('3')); - assert.ok(!map.get('4')); - assert.ok(!map.get('5')); - - map.set('6', 6); - - assert.equal(map.size, 0); - assert.ok(!map.get('6')); - - map.setLimit(100); - - map.set('1', 1); - map.set('2', '2'); - map.set('3', true); - map.set('4', obj); - map.set('5', date); - - assert.equal(map.size, 5); - assert.equal(map.get('1'), 1); - assert.equal(map.get('2'), '2'); - assert.equal(map.get('3'), true); - assert.equal(map.get('4'), obj); - assert.equal(map.get('5'), date); - }); - - test('BoundedMap - bounded', function () { - const map = new BoundedMap(5); - - assert.equal(0, map.size); - - map.set('1', 1); - map.set('2', 2); - map.set('3', 3); - map.set('4', 4); - map.set('5', 5); - - assert.equal(5, map.size); - - assert.equal(map.get('1'), 1); - assert.equal(map.get('2'), 2); - assert.equal(map.get('3'), 3); - assert.equal(map.get('4'), 4); - assert.equal(map.get('5'), 5); - - map.set('6', 6); - - assert.equal(5, map.size); - assert.ok(!map.get('1')); - assert.equal(map.get('2'), 2); - assert.equal(map.get('3'), 3); - assert.equal(map.get('4'), 4); - assert.equal(map.get('5'), 5); - assert.equal(map.get('6'), 6); - - map.set('7', 7); - map.set('8', 8); - map.set('9', 9); - - assert.equal(5, map.size); - assert.ok(!map.get('1')); - assert.ok(!map.get('2')); - assert.ok(!map.get('3')); - assert.ok(!map.get('4')); - - assert.equal(map.get('5'), 5); - assert.equal(map.get('6'), 6); - assert.equal(map.get('7'), 7); - assert.equal(map.get('8'), 8); - assert.equal(map.get('9'), 9); - - map.delete('5'); - map.delete('7'); - - assert.equal(3, map.size); - assert.ok(!map.get('5')); - assert.ok(!map.get('7')); - assert.equal(map.get('6'), 6); - assert.equal(map.get('8'), 8); - assert.equal(map.get('9'), 9); - - map.set('10', 10); - map.set('11', 11); - map.set('12', 12); - map.set('13', 13); - map.set('14', 14); - - assert.equal(5, map.size); - assert.equal(map.get('10'), 10); - assert.equal(map.get('11'), 11); - assert.equal(map.get('12'), 12); - assert.equal(map.get('13'), 13); - assert.equal(map.get('14'), 14); - }); - - test('BoundedMap - bounded with ratio', function () { - const map = new BoundedMap(6, 0.5); - - assert.equal(0, map.size); - - map.set('1', 1); - map.set('2', 2); - map.set('3', 3); - map.set('4', 4); - map.set('5', 5); - map.set('6', 6); - - assert.equal(6, map.size); - - map.set('7', 7); - - assert.equal(3, map.size); - assert.ok(!map.has('1')); - assert.ok(!map.has('2')); - assert.ok(!map.has('3')); - assert.ok(!map.has('4')); - assert.equal(map.get('5'), 5); - assert.equal(map.get('6'), 6); - assert.equal(map.get('7'), 7); - - map.set('8', 8); - map.set('9', 9); - map.set('10', 10); - - assert.equal(6, map.size); - assert.equal(map.get('5'), 5); - assert.equal(map.get('6'), 6); - assert.equal(map.get('7'), 7); - assert.equal(map.get('8'), 8); - assert.equal(map.get('9'), 9); - assert.equal(map.get('10'), 10); - }); - - test('BoundedMap - MRU order', function () { - const map = new BoundedMap(3); - - function peek(key) { - const res = map.get(key); - if (res) { - map.delete(key); - map.set(key, res); - } - - return res; - } - - assert.equal(0, map.size); - - map.set('1', 1); - map.set('2', 2); - map.set('3', 3); - - assert.equal(3, map.size); - - assert.equal(map.get('1'), 1); - assert.equal(map.get('2'), 2); - assert.equal(map.get('3'), 3); - - map.set('4', 4); - - assert.equal(3, map.size); - assert.equal(peek('4'), 4); // this changes MRU order - assert.equal(peek('3'), 3); - assert.equal(peek('2'), 2); - - map.set('5', 5); - map.set('6', 6); - - assert.equal(3, map.size); - assert.equal(peek('2'), 2); - assert.equal(peek('5'), 5); - assert.equal(peek('6'), 6); - assert.ok(!map.has('3')); - assert.ok(!map.has('4')); - }); - test('PathIterator', function () { const iter = new PathIterator(); iter.reset('file:///usr/bin/file.txt'); diff --git a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts index dd3e07e162c..556f60a0d87 100644 --- a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts @@ -29,7 +29,7 @@ import { registerEditorAction, EditorAction } from 'vs/editor/browser/editorExte import { IStorageService } from 'vs/platform/storage/common/storage'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { once } from 'vs/base/common/event'; -import { BoundedMap, ISerializedBoundedLinkedMap } from 'vs/base/common/map'; +import { LRUCache } from 'vs/base/common/map'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; @@ -39,9 +39,14 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; export const ALL_COMMANDS_PREFIX = '>'; let lastCommandPaletteInput: string; -let commandHistory: BoundedMap; +let commandHistory: LRUCache; let commandCounter = 1; +interface ISerializedCommandHistory { + usesLRU?: boolean; + entries: { key: string; value: number }[]; +} + function resolveCommandHistory(configurationService: IConfigurationService): number { const config = configurationService.getValue(); @@ -77,22 +82,31 @@ class CommandsHistory { this.commandHistoryLength = resolveCommandHistory(this.configurationService); if (commandHistory) { - commandHistory.setLimit(this.commandHistoryLength); + commandHistory.limit = this.commandHistoryLength; } } private load(): void { const raw = this.storageService.get(CommandsHistory.PREF_KEY_CACHE); - let deserializedCache: ISerializedBoundedLinkedMap; + let serializedCache: ISerializedCommandHistory; if (raw) { try { - deserializedCache = JSON.parse(raw); + serializedCache = JSON.parse(raw); } catch (error) { // invalid data } } - commandHistory = new BoundedMap(this.commandHistoryLength, 1, deserializedCache); + commandHistory = new LRUCache(this.commandHistoryLength, 1); + if (serializedCache) { + let entries: { key: string; value: number }[]; + if (serializedCache.usesLRU) { + entries = serializedCache.entries; + } else { + entries = serializedCache.entries.sort((a, b) => a.value - b.value); + } + entries.forEach(entry => commandHistory.set(entry.key, entry.value)); + } commandCounter = this.storageService.getInteger(CommandsHistory.PREF_KEY_COUNTER, void 0, commandCounter); } @@ -102,21 +116,19 @@ class CommandsHistory { } private save(): void { - this.storageService.store(CommandsHistory.PREF_KEY_CACHE, JSON.stringify(commandHistory.serialize())); + let serializedCache: ISerializedCommandHistory = { usesLRU: true, entries: [] }; + commandHistory.forEach((value, key) => serializedCache.entries.push({ key, value })); + this.storageService.store(CommandsHistory.PREF_KEY_CACHE, JSON.stringify(serializedCache)); this.storageService.store(CommandsHistory.PREF_KEY_COUNTER, commandCounter); } public push(commandId: string): void { - - // make MRU by deleting it first - commandHistory.delete(commandId); - // set counter to command commandHistory.set(commandId, commandCounter++); } - public get(commandId: string): number { - return commandHistory.get(commandId); + public peek(commandId: string): number { + return commandHistory.peek(commandId); } } @@ -166,7 +178,7 @@ export class ClearCommandHistoryAction extends Action { public run(context?: any): TPromise { const commandHistoryLength = resolveCommandHistory(this.configurationService); if (commandHistoryLength > 0) { - commandHistory = new BoundedMap(commandHistoryLength); + commandHistory = new LRUCache(commandHistoryLength); commandCounter = 1; } @@ -435,8 +447,8 @@ export class CommandsHandler extends QuickOpenHandler { // Sort by MRU order and fallback to name otherwie entries = entries.sort((elementA, elementB) => { - const counterA = this.commandsHistory.get(elementA.getCommandId()); - const counterB = this.commandsHistory.get(elementB.getCommandId()); + const counterA = this.commandsHistory.peek(elementA.getCommandId()); + const counterB = this.commandsHistory.peek(elementB.getCommandId()); if (counterA && counterB) { return counterA > counterB ? -1 : 1; // use more recently used command before older @@ -457,11 +469,11 @@ export class CommandsHandler extends QuickOpenHandler { // Introduce group marker border between recently used and others // only if we have recently used commands in the result set const firstEntry = entries[0]; - if (firstEntry && this.commandsHistory.get(firstEntry.getCommandId())) { + if (firstEntry && this.commandsHistory.peek(firstEntry.getCommandId())) { firstEntry.setGroupLabel(nls.localize('recentlyUsed', "recently used")); for (let i = 1; i < entries.length; i++) { const entry = entries[i]; - if (!this.commandsHistory.get(entry.getCommandId())) { + if (!this.commandsHistory.peek(entry.getCommandId())) { entry.setShowBorder(true); entry.setGroupLabel(nls.localize('morecCommands', "other commands")); break; @@ -546,7 +558,7 @@ export class CommandsHandler extends QuickOpenHandler { if (autoFocusPrefixMatch && this.commandHistoryEnabled) { const firstEntry = context.model && context.model.entries[0]; - if (firstEntry instanceof BaseCommandEntry && this.commandsHistory.get(firstEntry.getCommandId())) { + if (firstEntry instanceof BaseCommandEntry && this.commandsHistory.peek(firstEntry.getCommandId())) { autoFocusPrefixMatch = void 0; // keep focus on MRU element if we have history elements } }