Skip to content

Commit

Permalink
Merge branch 'main' into fix/completion-in-the-middle-of-the-empty-text
Browse files Browse the repository at this point in the history
  • Loading branch information
Petr Spacek committed Apr 11, 2022
2 parents ef25120 + 9cfb0c7 commit 7e3e98d
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 31 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The following settings are supported:
- `http.proxyStrictSSL`: If true the proxy server certificate should be verified against the list of supplied CAs. Default is false.
- `[yaml].editor.formatOnType`: Enable/disable on type indent and auto formatting array
- `yaml.disableDefaultProperties`: Disable adding not required properties with default values into completion text
- `yaml.suggest.parentSkeletonSelectedFirst`: If true, the user must select some parent skeleton first before autocompletion starts to suggest the rest of the properties.\nWhen yaml object is not empty, autocompletion ignores this setting and returns all properties and skeletons.

##### Adding custom tags

Expand Down
5 changes: 5 additions & 0 deletions src/languageserver/handlers/settingsHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ export class SettingsHandler {
}
this.yamlSettings.disableAdditionalProperties = settings.yaml.disableAdditionalProperties;
this.yamlSettings.disableDefaultProperties = settings.yaml.disableDefaultProperties;

if (settings.yaml.suggest) {
this.yamlSettings.suggest.parentSkeletonSelectedFirst = settings.yaml.suggest.parentSkeletonSelectedFirst;
}
}

this.yamlSettings.schemaConfigurationSettings = [];
Expand Down Expand Up @@ -232,6 +236,7 @@ export class SettingsHandler {
indentation: this.yamlSettings.indentation,
disableAdditionalProperties: this.yamlSettings.disableAdditionalProperties,
disableDefaultProperties: this.yamlSettings.disableDefaultProperties,
parentSkeletonSelectedFirst: this.yamlSettings.suggest.parentSkeletonSelectedFirst,
yamlVersion: this.yamlSettings.yamlVersion,
};

Expand Down
62 changes: 49 additions & 13 deletions src/languageservice/services/yamlCompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ export class YamlCompletion {
private configuredIndentation: string | undefined;
private yamlVersion: YamlVersion;
private indentation: string;
private arrayPrefixIndentation = '';
private supportsMarkdown: boolean | undefined;
private disableDefaultProperties: boolean;
private parentSkeletonSelectedFirst: boolean;

constructor(
private schemaService: YAMLSchemaService,
Expand All @@ -89,6 +91,7 @@ export class YamlCompletion {
this.yamlVersion = languageSettings.yamlVersion;
this.configuredIndentation = languageSettings.indentation;
this.disableDefaultProperties = languageSettings.disableDefaultProperties;
this.parentSkeletonSelectedFirst = languageSettings.parentSkeletonSelectedFirst;
}

async doComplete(document: TextDocument, position: Position, isKubernetes = false): Promise<CompletionList> {
Expand Down Expand Up @@ -126,6 +129,7 @@ export class YamlCompletion {

const currentWord = this.getCurrentWord(document, offset);

this.arrayPrefixIndentation = '';
let overwriteRange: Range = null;
if (node && isScalar(node) && node.value === 'null') {
const nodeStartPos = document.positionAt(node.range[0]);
Expand All @@ -139,6 +143,9 @@ export class YamlCompletion {
start.character -= 1;
}
overwriteRange = Range.create(start, document.positionAt(node.range[1]));
} else if (node && isScalar(node) && node.value === null && currentWord === '-') {
overwriteRange = Range.create(position, position);
this.arrayPrefixIndentation = ' ';
} else {
let overwriteStart = document.offsetAt(position) - currentWord.length;
if (overwriteStart > 0 && document.getText()[overwriteStart - 1] === '"') {
Expand Down Expand Up @@ -219,6 +226,10 @@ export class YamlCompletion {
return;
}

if (this.arrayPrefixIndentation) {
this.updateCompletionText(completionItem, this.arrayPrefixIndentation + completionItem.insertText);
}

const existing = proposed[label];
const isInsertTextDifferent =
existing?.label !== existingProposeItem && existing?.insertText !== completionItem.insertText;
Expand Down Expand Up @@ -313,7 +324,7 @@ export class YamlCompletion {
}
}

const originalNode = node;
let originalNode = node;
if (node) {
// when the value is null but the cursor is between prop name and null value (cursor is not at the end of the line)
if (isMap(node) && node.items.length && isPair(node.items[0])) {
Expand All @@ -329,6 +340,18 @@ export class YamlCompletion {
overwriteRange.end.character += pairNode.value.range[2] - offset; // extend range to the end of the null element
}
}
// when the array item value is null but the cursor is between '-' and null value (cursor is not at the end of the line)
if (isSeq(node) && node.items.length && isScalar(node.items[0]) && lineContent.includes('-')) {
const nullNode = node.items[0];
if (
nullNode.value === null && // value is null
nullNode.range[0] > offset // cursor is before null
) {
node = nullNode;
originalNode = node;
overwriteRange.end.character += nullNode.range[2] - offset; // extend range to the end of the null element
}
}
if (lineContent.length === 0) {
node = currentDoc.internalDocument.contents as Node;
} else {
Expand Down Expand Up @@ -422,6 +445,13 @@ export class YamlCompletion {
// eslint-disable-next-line no-self-assign
currentDoc.internalDocument = currentDoc.internalDocument;
node = map;
} else if (lineContent.charAt(position.character - 1) === '-') {
const map = this.createTempObjNode('', node, currentDoc);
parent.delete(node);
parent.add(map);
// eslint-disable-next-line no-self-assign
currentDoc.internalDocument = currentDoc.internalDocument;
node = map;
} else {
node = parent;
}
Expand Down Expand Up @@ -561,9 +591,9 @@ export class YamlCompletion {
insertText = insertText.substring(0, insertText.length - 2);
}

completionItem.insertText = insertText;
completionItem.insertText = this.arrayPrefixIndentation + insertText;
if (completionItem.textEdit) {
completionItem.textEdit.newText = insertText;
completionItem.textEdit.newText = completionItem.insertText;
}
// remove $x or use {$x:value} in documentation
const mdText = insertText.replace(/\${[0-9]+[:|](.*)}/g, (s, arg) => arg).replace(/\$([0-9]+)/g, '');
Expand Down Expand Up @@ -603,7 +633,6 @@ export class YamlCompletion {
const lineContent = textBuffer.getLineContent(overwriteRange.start.line);
const hasOnlyWhitespace = lineContent.trim().length === 0;
const hasColon = lineContent.indexOf(':') !== -1;

const nodeParent = doc.getParent(node);
const matchOriginal = matchingSchemas.find((it) => it.node.internalNode === originalNode && it.schema.properties);
for (const schema of matchingSchemas) {
Expand Down Expand Up @@ -639,9 +668,11 @@ export class YamlCompletion {
const indexOfSlash = sourceText.lastIndexOf('-', node.range[0] - 1);
if (indexOfSlash >= 0) {
// add one space to compensate the '-'
identCompensation = ' ' + sourceText.slice(indexOfSlash + 1, node.range[0]);
const overwriteChars = overwriteRange.end.character - overwriteRange.start.character;
identCompensation = ' ' + sourceText.slice(indexOfSlash + 1, node.range[1] - overwriteChars);
}
}
identCompensation += this.arrayPrefixIndentation;

// if check that current node has last pair with "null" value and key witch match key from schema,
// and if schema has array definition it add completion item for array item creation
Expand Down Expand Up @@ -690,14 +721,19 @@ export class YamlCompletion {
identCompensation + this.indentation
);
}

collector.add({
kind: CompletionItemKind.Property,
label: key,
insertText,
insertTextFormat: InsertTextFormat.Snippet,
documentation: this.fromMarkup(propertySchema.markdownDescription) || propertySchema.description || '',
});
const isNodeNull =
(isScalar(originalNode) && originalNode.value === null) ||
(isMap(originalNode) && originalNode.items.length === 0);
const existsParentCompletion = schema.schema.required?.length > 0;
if (!this.parentSkeletonSelectedFirst || !isNodeNull || !existsParentCompletion) {
collector.add({
kind: CompletionItemKind.Property,
label: key,
insertText,
insertTextFormat: InsertTextFormat.Snippet,
documentation: this.fromMarkup(propertySchema.markdownDescription) || propertySchema.description || '',
});
}
// if the prop is required add it also to parent suggestion
if (schema.schema.required?.includes(key)) {
collector.add({
Expand Down
5 changes: 3 additions & 2 deletions src/languageservice/services/yamlSchemaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -626,8 +626,9 @@ export class YAMLSchemaService extends JSONSchemaService {
if (!content) {
const errorMessage = localize(
'json.schema.nocontent',
"Unable to load schema from '{0}': No content.",
toDisplayString(schemaUri)
"Unable to load schema from '{0}': No content. {1}",
toDisplayString(schemaUri),
unresolvedJsonSchema.errors
);
return new UnresolvedSchema(<JSONSchema>{}, [errorMessage]);
}
Expand Down
6 changes: 6 additions & 0 deletions src/languageservice/yamlLanguageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ export interface LanguageSettings {
*/
disableDefaultProperties?: boolean;

/**
* If true, the user must select some parent skeleton first before autocompletion starts to suggest the rest of the properties.
* When yaml object is not empty, autocompletion ignores this setting and returns all properties and skeletons.
*/
parentSkeletonSelectedFirst?: boolean;

/**
* Default yaml lang version
*/
Expand Down
6 changes: 6 additions & 0 deletions src/yamlSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export interface Settings {
};
disableDefaultProperties: boolean;
disableAdditionalProperties: boolean;
suggest: {
parentSkeletonSelectedFirst: boolean;
};
maxItemsComputed: number;
yamlVersion: YamlVersion;
};
Expand Down Expand Up @@ -69,6 +72,9 @@ export class SettingsState {
indentation: string | undefined = undefined;
disableAdditionalProperties = false;
disableDefaultProperties = false;
suggest = {
parentSkeletonSelectedFirst: false,
};
maxItemsComputed = 5000;

// File validation helpers
Expand Down
Loading

0 comments on commit 7e3e98d

Please sign in to comment.