Skip to content

Add Throws to doc comment template #967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 8 additions & 4 deletions src/editor/CommentCompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ class FunctionDocumentationCompletionProvider implements vscode.CompletionItemPr
const funcPosition = new vscode.Position(position.line + 1, 0);
const details = this.getFunctionDetails(document, funcPosition);
if (details) {
if (details.parameters.length === 0 && details.returns === false) {
if (
details.parameters.length === 0 &&
details.returns === false &&
details.throws === false
) {
return undefined;
}
const snippet = this.constructSnippet(details, false);
Expand All @@ -109,7 +113,7 @@ class FunctionDocumentationCompletionProvider implements vscode.CompletionItemPr
if (details) {
const snippet = this.constructSnippet(details, true);
const insertPosition = new vscode.Position(line, details.indent);
editor.insertSnippet(snippet, insertPosition);
await editor.insertSnippet(snippet, insertPosition);
}
}

Expand Down Expand Up @@ -208,10 +212,10 @@ class FunctionDocumentationCompletionProvider implements vscode.CompletionItemPr
snippetIndex++;
}
}
/*if (details.throws) {
if (details.throws) {
string += `\n/// - Throws: $${snippetIndex}`;
snippetIndex++;
}*/
}
if (details.returns) {
string += `\n/// - Returns: $${snippetIndex}`;
}
Expand Down
241 changes: 241 additions & 0 deletions test/suite/editor/CommentCompletion.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the VS Code Swift open source project
//
// Copyright (c) 2023 the VS Code Swift project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of VS Code Swift project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import * as assert from "assert";
import * as vscode from "vscode";
import { CommentCompletionProviders } from "../../../src/editor/CommentCompletion";

suite("CommentCompletion Test Suite", () => {
let document: vscode.TextDocument | undefined;
let provider: CommentCompletionProviders;

setup(() => {
provider = new CommentCompletionProviders();
});

teardown(async () => {
const editor = vscode.window.visibleTextEditors.find(
editor => editor.document === document
);

if (editor && document) {
await vscode.window.showTextDocument(document, editor.viewColumn);
await vscode.commands.executeCommand("workbench.action.closeActiveEditor");
}

provider.dispose();
});

test("Completion on line that isn't a comment", async () => {
const { document, positions } = await openDocument(`
1️⃣
func foo() {}`);
const position = positions["1️⃣"];

const items = await provider.functionCommentCompletion.provideCompletionItems(
document,
position
);
assert.deepEqual(items, undefined);
});

test("Comment completion on line that isn't a function", async () => {
const { document, positions } = await openDocument(`
/// 1️⃣
let x = 1`);
const position = positions["1️⃣"];

const items = await provider.functionCommentCompletion.provideCompletionItems(
document,
position
);
assert.deepEqual(items, undefined);
});

test("Comment completion on func with no argument, no return should have no completions", async () => {
const { document, positions } = await openDocument(`
/// 1️⃣
func foo() {}`);
const position = positions["1️⃣"];

const items = await provider.functionCommentCompletion.provideCompletionItems(
document,
position
);
assert.deepEqual(items, undefined);
});

test("Comment completion on single argument function, no return should have a completion", async () => {
const { document, positions } = await openDocument(`
/// 1️⃣
func foo(bar: Int) {}`);
const position = positions["1️⃣"];

const items = await provider.functionCommentCompletion.provideCompletionItems(
document,
position
);
assert.deepEqual(items, [
expectedCompletionItem(` $1
/// - Parameter bar: $2`),
]);
});

test("Comment completion on single argument function, with return should have a completion", async () => {
const { document, positions } = await openDocument(`
/// 1️⃣
func foo(bar: Int) -> Int { return 0 }`);
const position = positions["1️⃣"];

const items = await provider.functionCommentCompletion.provideCompletionItems(
document,
position
);
assert.deepEqual(items, [
expectedCompletionItem(` $1
/// - Parameter bar: $2
/// - Returns: $3`),
]);
});

test("Comment completion on a throwing function", async () => {
const { document, positions } = await openDocument(`
/// 1️⃣
func foo() throws {}`);
const position = positions["1️⃣"];

const items = await provider.functionCommentCompletion.provideCompletionItems(
document,
position
);
assert.deepEqual(items, [
expectedCompletionItem(` $1
/// - Throws: $2`),
]);
});

test("Comment completion on single argument throwing function", async () => {
const { document, positions } = await openDocument(`
/// 1️⃣
func foo(bar: Int) throws {}`);
const position = positions["1️⃣"];

const items = await provider.functionCommentCompletion.provideCompletionItems(
document,
position
);
assert.deepEqual(items, [
expectedCompletionItem(` $1
/// - Parameter bar: $2
/// - Throws: $3`),
]);
});

test("Comment completion on complex function", async () => {
const { document, positions } = await openDocument(`
/// 1️⃣
func foo(bar: Int, baz: String) -> Data throws { return Data() }`);
const position = positions["1️⃣"];

const items = await provider.functionCommentCompletion.provideCompletionItems(
document,
position
);
assert.deepEqual(items, [
expectedCompletionItem(
` $1
/// - Parameters:
/// - bar: $2
/// - baz: $3
/// - Returns: $4`
),
]);
});

test("Comment Insertion", async () => {
const { document, positions } = await openDocument(`
/// 1️⃣
func foo(bar: Int, baz: String) -> Data throws { return Data() }`);
const position = positions["1️⃣"];

const editor = await vscode.window.showTextDocument(document);
await provider.insert(editor, position.line + 1);

assert.deepEqual(
editor.document.getText(),
`
/// !
/// !
/// - Parameters:
/// - bar: !
/// - baz: !
/// - Returns: !
func foo(bar: Int, baz: String) -> Data throws { return Data() }`.replace(/!/g, "")
); // ! ensures trailing white space is not trimmed when this file is formatted.
});

function expectedCompletionItem(snippet: string): vscode.CompletionItem {
const expected = new vscode.CompletionItem(
"/// - parameters:",
vscode.CompletionItemKind.Text
);
expected.detail = "Function documentation comment";
expected.insertText = new vscode.SnippetString(snippet);
expected.sortText = undefined;
return expected;
}

async function openDocument(content: string): Promise<{
document: vscode.TextDocument;
positions: { [key: string]: vscode.Position };
}> {
function positionOf(str: string, content: string): vscode.Position | undefined {
const lines = content.split("\n");
const line = lines.findIndex(line => line.includes(str));
if (line === -1) {
return;
}

const column = lines[line].indexOf(str);
return new vscode.Position(line, column);
}

let purgedContent = content;
const needles = ["1️⃣", "2️⃣", "3️⃣", "4️⃣"];

// Find all the needles, capture their positions and then remove them from
// the document before creating a vscode.TextDocument.
const positions = needles.reduce(
(prev, needle) => {
const pos = positionOf(needle, content);
if (pos) {
purgedContent = purgedContent.replace(needle, "");
prev[needle] = pos;
}
return prev;
},
{} as { [key: string]: vscode.Position }
);

const doc = await vscode.workspace.openTextDocument({
language: "swift",
content: purgedContent,
});

// Save the document so we can clean it up when the test finishes
document = doc;

return { document: doc, positions };
}
});