Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
- [A comment can be attached to the asset version][14923]
- [New tabular view of session log with filtering][14953]
- [Input ports no longer highlight on hover unless being connected to][14968]
- [Fix duplicated entries in Component Browser][14974]. The overshadowed methods
from parent types are no longer displayed.

[14590]: https://github.com/enso-org/enso/pull/14590
[14678]: https://github.com/enso-org/enso/pull/14678
Expand All @@ -34,6 +36,7 @@
[14823]: https://github.com/enso-org/enso/pull/14823
[14953]: https://github.com/enso-org/enso/pull/14953
[14968]: https://github.com/enso-org/enso/pull/14968
[14974]: https://github.com/enso-org/enso/pull/14974

#### Enso Standard Library

Expand Down
10 changes: 7 additions & 3 deletions app/gui/integration-test/project-view/widgets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1038,16 +1038,20 @@ test('Table widget', async ({ editorPage, page }) => {
await expect(widget.locator('.ag-cell')).toHaveText(['0', '', ''])

// Putting first value
await widget.locator('.ag-cell', { hasNotText: '0' }).first().click()
const firstValueCell = widget.locator('.ag-cell', { hasNotText: '0' }).first()
await firstValueCell.click()
await expect(firstValueCell).toBeFocused()
await page.keyboard.type('Value')
await page.keyboard.press('Enter')
// There will be new blank row allowing adding new rows.
await expect(widget.locator('.ag-cell')).toHaveText(['0', 'Value', '', '1', '', ''])

// Renaming column
await widget.locator('.ag-header-cell-text', { hasText: 'Column 1' }).first().click()
await page.keyboard.type('Header')
await page.keyboard.press('Enter')
const headerInput = widget.locator('.ag-text-field-input')
await expect(headerInput).toBeFocused()
await headerInput.fill('Header')
await headerInput.press('Enter')
await expect(widget.locator('.ag-header-cell-text')).toHaveText(['#', 'Header'])

// Adding next column
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,22 @@ test('`Any` type methods taken into account when filtering', () => {
expect(filteringWithoutSelfType.filter(entry2, db)).toBeNull()
})

test('`Any` or ancestor type methods may be overshadowed', () => {
const entry1 = makeMethod('Standard.Table.Column.Column.is_nothing')
const entry2 = makeMethod('Standard.Base.Any.Any.is_nothing')
const entry3 = makeMethod('Standard.Database.DB_Column.is_nothing')
const filtering = new Filtering({
selfArg: {
type: 'known',
typeInfo: TypeInfo.fromParsedTypes([stdPath('Standard.Table.Column.Column')], [])!,
ancestors: [stdPath('Standard.Database.DB_Column')],
},
})
const db = SuggestionDb.createMock([entry1, entry2, entry3])
expect(filtering.filter(entry1, db)).not.toBeNull()
expect(filtering.filter(entry2, db)).toBeNull()
})

test('Hidden self types and ancestors are taken into account when filtering', () => {
const entry1 = makeMethod('Standard.Base.Data.Numbers.Float.abs')
const entry2 = makeMethod('Standard.Base.Data.Numbers.Number.sqrt')
Expand Down Expand Up @@ -349,10 +365,7 @@ describe('Constructor fields accessors', () => {
const constructor = createConstructor('Standard.Base.Data.Json.JS_Object.Value', false)
const fieldAccessor = makeMethod('Standard.Base.Data.Json.JS_Object.object_node')
const typeMethod = makeMethod('Standard.Base.Data.Json.JS_Object.some_method')
const db = new SuggestionDb()
db.set(0, constructor)
db.set(1, fieldAccessor)
db.set(2, typeMethod)
const db = SuggestionDb.createMock([constructor, fieldAccessor, typeMethod])
expect(filtering.filter(fieldAccessor, db)).not.toBeNull()
expect(filtering.filter(typeMethod, db)).not.toBeNull()
})
Expand All @@ -361,10 +374,7 @@ describe('Constructor fields accessors', () => {
const constructor = createConstructor('Standard.Base.Data.Json.JS_Object.Value', true)
const fieldAccessor = makeMethod('Standard.Base.Data.Json.JS_Object.object_node')
const typeMethod = makeMethod('Standard.Base.Data.Json.JS_Object.some_method')
const db = new SuggestionDb()
db.set(0, constructor)
db.set(1, fieldAccessor)
db.set(2, typeMethod)
const db = SuggestionDb.createMock([constructor, fieldAccessor, typeMethod])
expect(filtering.filter(fieldAccessor, db)).toBeNull()
expect(filtering.filter(typeMethod, db)).not.toBeNull()
})
Expand All @@ -374,13 +384,10 @@ describe('Constructor fields accessors', () => {
const constructor2 = createConstructor('Standard.Base.Data.Json.JS_Object.PublicValue', false)
const fieldAccessor = makeMethod('Standard.Base.Data.Json.JS_Object.object_node')
const typeMethod = makeMethod('Standard.Base.Data.Json.JS_Object.some_method')
const db = new SuggestionDb()
db.set(0, constructor1)
db.set(1, fieldAccessor)
db.set(2, typeMethod)
const db = SuggestionDb.createMock([constructor1, fieldAccessor, typeMethod])
expect(filtering.filter(fieldAccessor, db)).toBeNull()
expect(filtering.filter(typeMethod, db)).not.toBeNull()
db.set(3, constructor2)
db.set(33, constructor2)
expect(filtering.filter(fieldAccessor, db)).not.toBeNull()
expect(filtering.filter(typeMethod, db)).not.toBeNull()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export class Filtering {
pattern: FilteringWithPattern | undefined
selfArg: SelfArg | undefined

/** TODO: Add docs */
/** Create filtering class. */
constructor(
filter: Filter,
public currentModule: ProjectPath | undefined = undefined,
Expand All @@ -277,7 +277,7 @@ export class Filtering {
this.selfArg = selfArg
}

private selfTypeMatches(entry: SuggestionEntry): MatchResult | null {
private selfTypeMatches(entry: SuggestionEntry, db: SuggestionDb): MatchResult | null {
if (this.selfArg == null)
return entry.kind !== SuggestionKind.Method || entry.selfType == null ? exactMatch() : null
if (entry.kind !== SuggestionKind.Method || entry.selfType == null) return null
Expand All @@ -287,14 +287,21 @@ export class Filtering {
const visibleTypeMatch = visibleTypes?.find((ty) => entrySelfType.equals(ty))
if (visibleTypeMatch != null) return exactMatch()
const hiddenTypeMatch = this.selfArg.typeInfo?.hiddenTypes.find((t) => entrySelfType.equals(t))
const matchedAncestor = this.selfArg.ancestors.find((t) => entrySelfType.equals(t))
if (entrySelfType.equals(ANY_TYPE) || hiddenTypeMatch != null || matchedAncestor != null)
// Matched ancestor are not added to `fromType`, because type casting is not needed.
if (hiddenTypeMatch != null) {
return { score: DIFFERENT_TYPE_PENALTY, fromType: hiddenTypeMatch }
return null
}
const matchedAncestor =
entrySelfType.equals(ANY_TYPE) ? ANY_TYPE : (
this.selfArg.ancestors.find((t) => entrySelfType.equals(t))
)
if (matchedAncestor == null) return null
const ancestorOvershadowed = db.conflictingMethods.lookup(entry.name).has(matchedAncestor.key())
if (ancestorOvershadowed) return null
// Matched ancestor are not added to `fromType`, because type casting is not needed.
return { score: DIFFERENT_TYPE_PENALTY, fromType: undefined }
}

/** TODO: Add docs */
/** Check if current filter is clear, and a "Main" view of the CB should be displayed. */
isMainView() {
return this.pattern == null && this.selfArg == null
}
Expand All @@ -321,7 +328,7 @@ export class Filtering {
filter(entry: SuggestionEntry, db: SuggestionDb): MatchResult | null {
if (entry.isPrivate || entry.kind != SuggestionKind.Method) return null
if (this.selfArg == null && isInternal(entry)) return null
let result = this.selfTypeMatches(entry)
let result = this.selfTypeMatches(entry, db)
if (result == null) return null
if (this.pattern) {
const additionalSelfTypes =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export class SuggestionDb extends ReactiveDb<SuggestionId, SuggestionEntry> {
return []
})
readonly conflictingNames = new ReactiveIndex(this, (id, entry) => [[entry.name, id]])
readonly conflictingMethods = new ReactiveIndex(this, (_, entry): [string, string][] =>
entry.kind === SuggestionKind.Method && entry.selfType != null ?
[[entry.name, entry.selfType.key()]]
: [],
)
private readonly suggestionsByKind = new ReactiveIndex(this, (id, entry) => [[entry.kind, id]])
private readonly constructorFields = new ReactiveIndex(this, (id, entry) => {
if (entry.kind !== SuggestionKind.Constructor) return []
Expand All @@ -64,6 +69,13 @@ export class SuggestionDb extends ReactiveDb<SuggestionId, SuggestionEntry> {
super()
}

/** Create database filled with entries. */
static createMock(entries: SuggestionEntry[]) {
const db = new SuggestionDb()
entries.forEach((entry, i) => db.set(i, entry))
return db
}

/** Retrieve all suggestions of the given kind stored in the suggestion database. */
private *getAllEntriesOfKind<K extends SuggestionKind>(
kind: K,
Expand Down
Loading