wip
This commit is contained in:
parent
9b57304b87
commit
d195c5321c
|
|
@ -90,7 +90,7 @@ describe('autocomplete function names', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('autocomplete function arguments', () => {
|
||||
describe('autocomplete positional arguments', () => {
|
||||
test('shows args for shrimp function', () => {
|
||||
const args = getArgsInScope(`
|
||||
add = do x y: x + y end
|
||||
|
|
@ -123,6 +123,44 @@ describe('autocomplete function arguments', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('autocomplete named arguments', () => {
|
||||
test('shows remaining args after positional arg used', () => {
|
||||
const args = getArgsInScope(`
|
||||
add = do alpha bravo charlie: alpha + bravo + charlie end
|
||||
add 5 <cursor>
|
||||
`)
|
||||
// alpha is used positionally
|
||||
expect(args).toEqual(['bravo', 'charlie'])
|
||||
})
|
||||
|
||||
test('filters args by prefix when typing', () => {
|
||||
const args = getArgsInScope(`
|
||||
add = do alpha bravo charlie: alpha + bravo + charlie end
|
||||
add 5 b<cursor>
|
||||
`)
|
||||
// alpha is used, typing 'b' filters to bravo
|
||||
expect(args).toEqual(['bravo'])
|
||||
})
|
||||
|
||||
test('excludes named arg already used', () => {
|
||||
const args = getArgsInScope(`
|
||||
add = do alpha bravo charlie: alpha + bravo + charlie end
|
||||
add bravo=10 <cursor>
|
||||
`)
|
||||
// bravo is used as named arg
|
||||
expect(args).toEqual(['alpha', 'charlie'])
|
||||
})
|
||||
|
||||
test('positional fills first slot, skips named args', () => {
|
||||
const args = getArgsInScope(`
|
||||
add = do alpha bravo charlie: alpha + bravo + charlie end
|
||||
add bravo=5 <cursor>
|
||||
`)
|
||||
// bravo is named, 10 fills alpha (first positional slot)
|
||||
expect(args).toEqual(['alpha', 'charlie'])
|
||||
})
|
||||
})
|
||||
|
||||
// Helper functions
|
||||
|
||||
const getVarsInScope = (codeWithCursor: string): CompletionItem[] => {
|
||||
|
|
@ -163,7 +201,3 @@ const getArgsInScope = (codeWithCursor: string): string[] => {
|
|||
|
||||
return items.map((v) => v.name)
|
||||
}
|
||||
|
||||
const getArgItems = (codeWithCursor: string): CompletionItem[] => {
|
||||
return getVarsInScope(codeWithCursor).filter((v) => v.kind === 'arg')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,16 +42,19 @@ const autocompleteArg = (view: EditorView, context: FunctionCallContext): Comple
|
|||
return []
|
||||
}
|
||||
|
||||
// Count how many positional args have already been used
|
||||
// Collect used args
|
||||
const usedPositionalArgs = countPositionalArgs(context.fnCallNode, cursor)
|
||||
const usedNamedArgs = collectUsedNamedArgs(context.fnCallNode, cursor, view)
|
||||
|
||||
if (fn.kind === 'shrimp-fn') {
|
||||
// Skip params that have already been filled positionally
|
||||
const remainingParams = fn.params.slice(usedPositionalArgs)
|
||||
// Filter out named args, then skip positional slots
|
||||
const availableParams = fn.params.filter((p) => !usedNamedArgs.has(p))
|
||||
const remainingParams = availableParams.slice(usedPositionalArgs)
|
||||
return remainingParams.map((paramName) => ({ kind: 'arg', name: paramName }))
|
||||
} else if (fn.kind === 'nose-command') {
|
||||
// Skip params that have already been filled positionally
|
||||
const remainingParams = fn.def.signature.params.slice(usedPositionalArgs)
|
||||
// Filter out named args, then skip positional slots
|
||||
const availableParams = fn.def.signature.params.filter((p) => !usedNamedArgs.has(p.name))
|
||||
const remainingParams = availableParams.slice(usedPositionalArgs)
|
||||
return remainingParams.map((param) => ({
|
||||
kind: 'arg',
|
||||
name: param.name,
|
||||
|
|
@ -266,6 +269,32 @@ const countPositionalArgs = (fnCallNode: SyntaxNode, cursor: number): number =>
|
|||
return count
|
||||
}
|
||||
|
||||
const collectUsedNamedArgs = (
|
||||
fnCallNode: SyntaxNode,
|
||||
cursor: number,
|
||||
view: EditorView
|
||||
): Set<string> => {
|
||||
const usedNames = new Set<string>()
|
||||
let child = fnCallNode.firstChild
|
||||
|
||||
while (child) {
|
||||
// Only collect NamedArg nodes that end before cursor
|
||||
if (child.type.id === Terms.NamedArg && child.to <= cursor) {
|
||||
// Find the NamedArgPrefix child which contains "paramname="
|
||||
const prefixNode = child.firstChild
|
||||
if (prefixNode?.type.id === Terms.NamedArgPrefix) {
|
||||
const prefixText = view.state.doc.sliceString(prefixNode.from, prefixNode.to)
|
||||
// Remove the trailing '=' to get the param name
|
||||
const paramName = prefixText.slice(0, -1)
|
||||
usedNames.add(paramName)
|
||||
}
|
||||
}
|
||||
child = child.nextSibling
|
||||
}
|
||||
|
||||
return usedNames
|
||||
}
|
||||
|
||||
type ShrimpFn = {
|
||||
kind: 'shrimp-fn'
|
||||
name: string
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user