Skip to content
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

Documentation in the VSCode - core, std, and current project #1466

Merged
merged 23 commits into from
May 13, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 37 additions & 6 deletions compiler/qsc_doc_gen/src/generate_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ mod tests;
use crate::display::{increase_header_level, parse_doc_for_summary};
use crate::display::{CodeDisplay, Lookup};
use qsc_ast::ast;
use qsc_data_structures::language_features::LanguageFeatures;
use qsc_data_structures::target::TargetCapabilityFlags;
use qsc_frontend::compile::{self, PackageStore};
use qsc_frontend::compile::{self, compile, PackageStore, SourceMap};
use qsc_frontend::resolve;
use qsc_hir::hir::{CallableKind, Item, ItemKind, Package, PackageId, Visibility};
use qsc_hir::{hir, ty};
Expand All @@ -27,10 +28,34 @@ struct Compilation {
}

impl Compilation {
/// Creates a new `Compilation` by compiling sources.
pub(crate) fn new() -> Self {
/// Creates a new `Compilation` by compiling standard library
/// and additional sources.
pub(crate) fn new(
additional_sources: Option<SourceMap>,
DmitryVasilevsky marked this conversation as resolved.
Show resolved Hide resolved
capabilities: Option<TargetCapabilityFlags>,
language_features: Option<LanguageFeatures>,
) -> Self {
let mut package_store = PackageStore::new(compile::core());
package_store.insert(compile::std(&package_store, TargetCapabilityFlags::all()));
let actual_capabilities = capabilities.unwrap_or_default();
let std_unit = compile::std(&package_store, actual_capabilities);
let std_package_id = package_store.insert(std_unit);

if let Some(sources) = additional_sources {
let actual_language_features = language_features.unwrap_or_default();

let unit = compile(
&package_store,
&[std_package_id],
sources,
actual_capabilities,
actual_language_features,
);
// We ignore errors here (unit.errors vector) and use whatever
// documentation we can produce. In future we may consider
// displaying the fact of error presence on documentation page.

package_store.insert(unit);
}

Self { package_store }
}
Expand Down Expand Up @@ -103,9 +128,15 @@ impl Lookup for Compilation {
}
}

/// Generates and returns documentation files for the standard library
/// and additional sources (if specified.)
#[must_use]
pub fn generate_docs() -> Files {
let compilation = Compilation::new();
pub fn generate_docs(
additional_sources: Option<SourceMap>,
capabilities: Option<TargetCapabilityFlags>,
language_features: Option<LanguageFeatures>,
) -> Files {
let compilation = Compilation::new(additional_sources, capabilities, language_features);
let mut files: Files = vec![];

let display = &CodeDisplay {
Expand Down
2 changes: 1 addition & 1 deletion compiler/qsc_doc_gen/src/generate_docs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use expect_test::expect;

#[test]
fn docs_generation() {
let files = generate_docs();
let files = generate_docs(None, None, None);
let (_, metadata, contents) = files
.iter()
.find(|(file_name, _, _)| &**file_name == "Microsoft.Quantum.Core/Length.md")
Expand Down
22 changes: 19 additions & 3 deletions npm/qsharp/src/compiler/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ export interface ICompiler {
operation?: IOperationInfo,
): Promise<CircuitData>;

getDocumentation(): Promise<IDocFile[]>;
getDocumentation(
additionalSources?: [string, string][],
targetProfile?: string,
languageFeatures?: string[],
): Promise<IDocFile[]>;

checkExerciseSolution(
userCode: string,
Expand Down Expand Up @@ -273,8 +277,20 @@ export class Compiler implements ICompiler {
);
}

async getDocumentation(): Promise<IDocFile[]> {
return this.wasm.generate_docs();
// Returns all autogenerated documentation files for the standard library
// and loaded project (if requested). This include file names and metadata,
// including specially formatted table of content file.
async getDocumentation(
additionalSources?: [string, string][],
targetProfile?: string,
languageFeatures?: string[],
): Promise<IDocFile[]> {
// Get documentation from wasm layer
return this.wasm.generate_docs(
additionalSources,
targetProfile,
languageFeatures,
);
}

async checkExerciseSolution(
Expand Down
2 changes: 1 addition & 1 deletion playground/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function copyLibs() {
mkdirSync(monacoDest, { recursive: true });
cpSync(monacoBase, monacoDest, { recursive: true });

copyKatex(join(thisDir, "public/libs/katex"), true);
copyKatex(join(thisDir, "public/libs/katex"));
DmitryVasilevsky marked this conversation as resolved.
Show resolved Hide resolved

copyWasmToPlayground();
}
Expand Down
2 changes: 1 addition & 1 deletion playground/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
rel="icon"
href="data:image/gif;base64,R0lGODlhEAAQAAAAACwAAAAAEAAQAAACDvAxdbn9YZSTVntx1qcAADs="
/>
<link rel="stylesheet" href="libs/katex/github-markdown.css" />
<link rel="stylesheet" href="libs/katex/github-markdown-light.css" />
sezna marked this conversation as resolved.
Show resolved Hide resolved
<link rel="stylesheet" href="libs/katex/katex.min.css" />
<link rel="stylesheet" href="libs/main.css" />
<title>Q# playground</title>
Expand Down
8 changes: 8 additions & 0 deletions samples/algorithms/BellState.qs
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,31 @@ namespace Sample {
return measurements;
}

/// # Summary
/// Prepares |Φ+⟩ = (|00⟩+|11⟩)/√2 state assuming `register` is in |00⟩ state.
operation PreparePhiPlus(register : Qubit[]) : Unit {
H(register[0]); // |+0〉
CNOT(register[0], register[1]); // 1/sqrt(2)(|00〉 + |11〉)
}

/// # Summary
/// Prepares |Φ−⟩ = (|00⟩-|11⟩)/√2 state assuming `register` is in |00⟩ state.
operation PreparePhiMinus(register : Qubit[]) : Unit {
H(register[0]); // |+0〉
Z(register[0]); // |-0〉
CNOT(register[0], register[1]); // 1/sqrt(2)(|00〉 - |11〉)
}

/// # Summary
/// Prepares |Ψ+⟩ = (|01⟩+|10⟩)/√2 state assuming `register` is in |00⟩ state.
operation PreparePsiPlus(register : Qubit[]) : Unit {
H(register[0]); // |+0〉
X(register[1]); // |+1〉
CNOT(register[0], register[1]); // 1/sqrt(2)(|01〉 + |10〉)
}

/// # Summary
/// Prepares |Ψ−⟩ = (|01⟩-|10⟩)/√2 state assuming `register` is in |00⟩ state.
operation PreparePsiMinus(register : Qubit[]) : Unit {
H(register[0]); // |+0〉
Z(register[0]); // |-0〉
Expand Down
14 changes: 7 additions & 7 deletions vscode/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,8 @@ export function copyWasmToVsCode() {
/**
*
* @param {string} [destDir]
* @param {boolean} [useLightTheme]
*/
export function copyKatex(destDir, useLightTheme) {
export function copyKatex(destDir) {
let katexBase = join(libsDir, `katex/dist`);
let katexDest = destDir ?? join(thisDir, `out/katex`);

Expand All @@ -78,12 +77,13 @@ export function copyKatex(destDir, useLightTheme) {
);

// Also copy the GitHub markdown CSS
const cssFileName = useLightTheme
? "github-markdown-light.css"
: "github-markdown.css";
copyFileSync(
join(libsDir, `github-markdown-css/${cssFileName}`),
join(katexDest, "github-markdown.css"),
join(libsDir, `github-markdown-css/github-markdown-light.css`),
join(katexDest, "github-markdown-light.css"),
);
copyFileSync(
join(libsDir, `github-markdown-css/github-markdown-dark.css`),
join(katexDest, "github-markdown-dark.css"),
sezna marked this conversation as resolved.
Show resolved Hide resolved
);

const fontsDir = join(katexBase, "fonts");
Expand Down
9 changes: 9 additions & 0 deletions vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@
"command": "qsharp-vscode.showCircuit",
"when": "resourceLangId == qsharp"
},
{
"command": "qsharp-vscode.showDocumentation",
"when": "resourceLangId == qsharp"
},
{
"command": "qsharp-vscode.setTargetProfile",
"when": "resourceLangId == qsharp"
Expand Down Expand Up @@ -316,6 +320,11 @@
"title": "Show circuit",
"category": "Q#"
},
{
"command": "qsharp-vscode.showDocumentation",
"title": "Show API documentation",
"category": "Q#"
},
{
"command": "qsharp-vscode.workspacesRefresh",
"category": "Q#",
Expand Down
61 changes: 61 additions & 0 deletions vscode/src/documentation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { getCompilerWorker } from "qsharp-lang";
import { isQsharpDocument } from "./common";
import { getTarget } from "./config";
import { Uri, window } from "vscode";
import { loadProject } from "./projectSystem";
import { sendMessageToPanel } from "./webviewPanel";

export async function showDocumentationCommand(extensionUri: Uri) {
const editor = window.activeTextEditor;
if (!editor || !isQsharpDocument(editor.document)) {
throw new Error("The currently active window is not a Q# file");
}

// Reveal panel and show 'Loading...' for immediate feedback.
sendMessageToPanel(
"documentation", // This is needed to route the message to the proper panel
true, // Reveal panel
null, // With no message
);

const docUri = editor.document.uri;
const program = await loadProject(docUri);
const targetProfile = getTarget();

// Get API documentation from compiler.
const compilerWorkerScriptPath = Uri.joinPath(
extensionUri,
"./out/compilerWorker.js",
).toString();
const worker = getCompilerWorker(compilerWorkerScriptPath);
const docFiles = await worker.getDocumentation(
program.sources,
targetProfile,
program.languageFeatures,
);

const documentation: string[] = [];
for (const file of docFiles) {
// Some files may contain information other than documentation
// For example, table of content is a separate file in a special format
// We check presence of qsharp.name in metadata to make sure we take
// only files that contain documentation from some qsharp object.
if (file.metadata.indexOf("qsharp.name:") >= 0) {
documentation.push(file.contents);
}
}

const message = {
command: "showDocumentationCommand", // This is handled in webview.tsx onMessage
fragmentsToRender: documentation,
};

sendMessageToPanel(
"documentation", // This is needed to route the message to the proper panel
true, // Reveal panel
message, // And ask it to display documentation
);
}
14 changes: 14 additions & 0 deletions vscode/src/webview/docview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { Markdown } from "qsharp-lang/ux";

export function DocumentationView(props: { fragmentsToRender: string[] }) {
// Concatenate all documentation.
// The following adds an empty line and a horizontal line
// between documentation for different functions.
// We may consider filtering of fragments later.
const contentToRender = props.fragmentsToRender.join("<br/>\n\n---\n\n");

return <Markdown markdown={contentToRender} />;
}