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

Bitbucket normalizer #168

Merged
merged 10 commits into from
Nov 17, 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
35 changes: 19 additions & 16 deletions browser.webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ const browserClientConfig = /** @type WebpackConfig */ {
extensions: ['.ts', '.js'], // support ts-files and js-files
alias: {},
fallback: {
"fs": false,
"path": require.resolve("path-browserify")
},
"fs": false,
"path": require.resolve("path-browserify"),
"crypto": require.resolve("crypto-browserify"),
"vm": require.resolve("vm-browserify")
}
},
plugins: [
new ProvidePlugin({
Buffer: [require.resolve("buffer/"), "Buffer"],
}),
],
plugins: [
new ProvidePlugin({
Buffer: [require.resolve("buffer/"), "Buffer"],
}),
],
module: {
rules: [
{
Expand Down Expand Up @@ -71,16 +73,17 @@ const browserServerConfig = /** @type WebpackConfig */ {
mainFields: ['module', 'main'],
extensions: ['.ts', '.js'], // support ts-files and js-files
alias: {
glob: false,
},
glob: false,
},
fallback: {
"path": require.resolve("path-browserify"),
"crypto": require.resolve("crypto-browserify"),
util: false,
fs: false,
child_process: false,
os: false,
assert: false
"crypto": require.resolve("crypto-browserify"),
"vm": require.resolve("vm-browserify"),
util: false,
fs: false,
child_process: false,
os: false,
assert: false
},
},
module: {
Expand Down
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@
"@types/vscode": "^1.91.0",
"buffer": "^6.0.3"
}
}
}
14 changes: 10 additions & 4 deletions client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import {Help} from "./help";
import {Config} from "./config";
import {Flows} from "./flows";
import {TestController} from "./test_controller";
import {registerBitbucket} from "./integrations";
import {registerNormalizer} from "./normalize";

let client: BaseLanguageClient;
let myStatusBarItem: vscode.StatusBarItem;
let highlight: Highlight;
let help: Help;
let flows: Flows;
let config: Config;
let disposeAll:()=>void|undefined;

function registerAsFsProvider(client: BaseLanguageClient) {
const toUri = (path: string) => Uri.file(path);
Expand Down Expand Up @@ -43,6 +46,7 @@ function registerAsFsProvider(client: BaseLanguageClient) {
}

export function activate(context: ExtensionContext) {
disposeAll = () => context.subscriptions.forEach(async d => d.dispose());
myStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
myStatusBarItem.text = "abaplint";
myStatusBarItem.show();
Expand Down Expand Up @@ -122,14 +126,16 @@ export function activate(context: ExtensionContext) {
highlight.highlightWritesResponse(data.ranges, data.uri);
});
});

// removed, TODO: what was this used for?
// context.subscriptions.push(await client.start());
registerNormalizer(context, client);
registerBitbucket(client);
}

export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined;
}
return client.stop();
const stop = client.stop().then(() => client.dispose());
if (disposeAll) {disposeAll();}
return stop;
}

83 changes: 83 additions & 0 deletions client/src/integrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {extensions, Uri, workspace} from "vscode";
import {BaseLanguageClient} from "vscode-languageclient";

export const ATLASCODEDIFF = "atlascode.bbpr";
export interface CodeNormalizer {
isRelevant: (u: Uri) => boolean;
normalize: (code: string, uri: Uri) => Promise<string>;
}

export let integrationIsActive:(u:Uri) => boolean = () => false;
interface BitBucketApi {
registerCodeNormalizer:(n:CodeNormalizer)=>Disposable;
}

const shouldNormalize = (u:Uri) => {
try {
const o = JSON.parse(u.query);
return !! o.normalized;
} catch (error) {
return false;
}
};

const extractname = (u:Uri) => {
if (u.scheme !== ATLASCODEDIFF) {return u.path;}
try {
const details = JSON.parse(u.query);
if (details.path && typeof details.path === "string") {
return details.path;
}
} catch (error) {
return u.fragment;
}
};
const normalizations = ["On by default", "Off by default", "deactivated"] as const;
type Normalization<I extends number> = (typeof normalizations[I]);
const getNormalization = <I extends number>(): Normalization<I> => {
const n = workspace.getConfiguration("abaplint").get("codeNormalization") as any;
if (normalizations.includes(n)) {return n;}
return "Off by default";
};
const isAbap = (u:Uri) => !!(u.fsPath.match(/\.abap$/) || u.fragment.match(/\.abap$/));
export const getAbapCodeNormalizer = (client: BaseLanguageClient):CodeNormalizer => {
const normalization = getNormalization();
const inverted = normalization === "On by default";
const inactive = normalization === "deactivated";
return {
isRelevant:(u) => !inactive && isAbap(u),
normalize:async (source, uri) => {
if (inactive || !isAbap(uri) || (inverted === shouldNormalize(uri))) {
return source;
}
const path = extractname(uri);
try {
const formatted:string = await client.sendRequest("abaplint/normalize", {path, source});
return formatted;
} catch (error) {
return source;
}
},
};
};

// registers a code formatter for bitbucket using an API which will probably never be merged
// for now it's available on my fork of atlascode:
// https://bitbucket.org/marcellourbani/atlascode/branch/issue-%235433-Add-hook-to-pretty-print-code-to-show-in-diff-in-atlascode
// allows to:
// - normalize the code by default
// - get bitbucket functionality (i.e. comments) to work after normalizing
export const registerBitbucket = async (client: BaseLanguageClient) => {
const ext = extensions.getExtension<BitBucketApi>("atlassian.atlascode");
if (!ext) {
return;
}
if (!ext.isActive) {
await ext.activate();
}
if (ext.exports?.registerCodeNormalizer) {
const norm = getAbapCodeNormalizer(client);
integrationIsActive = (u) => u.scheme === ATLASCODEDIFF && norm.isRelevant(u);
ext.exports.registerCodeNormalizer(norm);
}
};
58 changes: 58 additions & 0 deletions client/src/normalize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {commands, ExtensionContext, TabInputTextDiff, TextEditor, Uri, window, TextDocumentContentProvider, Event, workspace} from "vscode";
import {BaseLanguageClient} from "vscode-languageclient";
import {ATLASCODEDIFF, CodeNormalizer, getAbapCodeNormalizer, integrationIsActive} from "./integrations";
const ABAPGITSCHEME = "abapgit.normalized";

const originalUri = (u:Uri) => {
if (u.scheme !== ABAPGITSCHEME) {return u;}
const {scheme, query} = JSON.parse(u.query);
return u.with({scheme, query});
};

class NormalizedProvider implements TextDocumentContentProvider {
private readonly normalizer: CodeNormalizer;
public constructor(client: BaseLanguageClient) {
this.normalizer = getAbapCodeNormalizer(client);
};
public onDidChange?: Event<Uri> | undefined;
public async provideTextDocumentContent(uri: Uri): Promise<string> {
const origUri = originalUri(uri);
if (uri.scheme === origUri.scheme) {throw new Error("invalid URL"); };
const raw = await workspace.openTextDocument(origUri);
return this.normalizer.normalize(raw.getText(), origUri);
}
}

const shouldActivate = (e: TextEditor | undefined) => {
const curtab = window.tabGroups.activeTabGroup;
const uri = e?.document.uri;
const isdiff = curtab.activeTab?.input instanceof TabInputTextDiff;
if (!(isdiff && uri)) {return false;}
const relevant =
uri.path.match(/\.abap$/) ||
uri.scheme === ATLASCODEDIFF && uri.fragment.match(/\.abap$/);
return relevant && !integrationIsActive(uri);
};

const activateNormalizer = (e: TextEditor | undefined) => {
commands.executeCommand("setContext", "abaplint.IsNormalizerEnabled", shouldActivate(e));
};
const toggleUrlNormalizer = (u:Uri) => {
if (u.scheme === ABAPGITSCHEME) { return originalUri(u);};
const query = JSON.stringify({scheme:u.scheme, query:u.query});
return u.with({scheme:ABAPGITSCHEME, query});
};

const toggleNormalizer = () => {
const curtab = window.tabGroups.activeTabGroup.activeTab;
if (!(curtab?.input instanceof TabInputTextDiff)) {return;}
const {original, modified} = curtab.input;
return commands.executeCommand<void>("vscode.diff", toggleUrlNormalizer(original), toggleUrlNormalizer(modified), curtab.label);
};

export const registerNormalizer = (context:ExtensionContext, client: BaseLanguageClient) => {
const onchg = window.onDidChangeActiveTextEditor(activateNormalizer);
const normalize = commands.registerCommand("abaplint.togglediffNormalize", toggleNormalizer);
const provider = workspace.registerTextDocumentContentProvider(ABAPGITSCHEME, new NormalizedProvider(client));
context.subscriptions.push(onchg, normalize, provider);
};
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@
"command": "abaplint.create.default-config",
"title": "Create Default Config",
"category": "abaplint"
},
{
"command": "abaplint.togglediffNormalize",
"title": "Normalize files",
"icon": "$(law)",
"category": "abaplint"
}
],
"jsonValidation": [
Expand Down Expand Up @@ -117,6 +123,11 @@
"when": "editorLangId == 'abap'",
"command": "abaplint.show",
"group": "navigation"
},
{
"command": "abaplint.togglediffNormalize",
"group": "navigation",
"when": "isInDiffEditor && abaplint.IsNormalizerEnabled"
}
],
"file/newFile": [
Expand Down Expand Up @@ -231,6 +242,22 @@
"description": "List of rules that should not be triggered on formatting"
}
}
},
{
"order": 50,
"id": "codenormalization",
"title": "Diff code normalization for bitbucket",
"properties": {
"abaplint.codeNormalization": {
"type": "string",
"enum": [
"On by default",
"Off by default",
"deactivated"
],
"default": "Off by default"
}
}
}
]
},
Expand Down Expand Up @@ -271,6 +298,7 @@
"path-browserify": "^1.0.1",
"ts-loader": "^9.5.1",
"typescript": "^5.6.3",
"vm-browserify": "^1.1.2",
"webpack": "^5.96.1",
"webpack-cli": "^5.1.4"
}
Expand Down
Loading