From 0e2051b538dd859836ca0781e7e92cb10d0b6828 Mon Sep 17 00:00:00 2001 From: Heyward Fann Date: Fri, 20 Oct 2023 11:51:54 +0800 Subject: [PATCH] feat(formatters): add ruff format support needs ruff 0.1.1, no stdin support by now --- package.json | 18 +++++++++++++++++- src/configSettings.ts | 1 + src/features/formatters/ruff.ts | 29 +++++++++++++++++++++++++++++ src/features/formatting.ts | 4 ++++ src/types.ts | 4 +++- 5 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/features/formatters/ruff.ts diff --git a/package.json b/package.json index ec3bab73..0a90d54b 100644 --- a/package.json +++ b/package.json @@ -1344,6 +1344,21 @@ "description": "Path to Black, you can use a custom version of Black by modifying this setting to include the full path.", "scope": "resource" }, + "python.formatting.ruffArgs": { + "type": "array", + "description": "Arguments passed in. Each argument is a separate item in the array.", + "default": [], + "items": { + "type": "string" + }, + "scope": "resource" + }, + "python.formatting.ruffPath": { + "type": "string", + "default": "ruff", + "description": "Path to ruff, you can use a custom version of ruff by modifying this setting to include the full path.", + "scope": "resource" + }, "python.formatting.pyinkArgs": { "type": "array", "description": "Arguments passed in. Each argument is a separate item in the array.", @@ -1356,7 +1371,7 @@ "python.formatting.pyinkPath": { "type": "string", "default": "pyink", - "description": "Path to Pyink, you can use a custom version of Black by modifying this setting to include the full path.", + "description": "Path to Pyink, you can use a custom version of pyink by modifying this setting to include the full path.", "scope": "resource" }, "python.formatting.darkerArgs": { @@ -1433,6 +1448,7 @@ "pyink", "blackd", "yapf", + "ruff", "none" ], "scope": "resource" diff --git a/src/configSettings.ts b/src/configSettings.ts index 9949e2aa..f88ad2f4 100644 --- a/src/configSettings.ts +++ b/src/configSettings.ts @@ -137,6 +137,7 @@ export class PythonSettings implements IPythonSettings { } this.formatting.autopep8Path = this.getAbsolutePath(systemVariables.resolveAny(this.formatting.autopep8Path)); this.formatting.yapfPath = this.getAbsolutePath(systemVariables.resolveAny(this.formatting.yapfPath)); + this.formatting.ruffPath = this.getAbsolutePath(systemVariables.resolveAny(this.formatting.ruffPath)); this.formatting.blackPath = this.getAbsolutePath(systemVariables.resolveAny(this.formatting.blackPath)); this.formatting.pyinkPath = this.getAbsolutePath(systemVariables.resolveAny(this.formatting.pyinkPath)); this.formatting.blackdPath = this.getAbsolutePath(systemVariables.resolveAny(this.formatting.blackdPath)); diff --git a/src/features/formatters/ruff.ts b/src/features/formatters/ruff.ts new file mode 100644 index 00000000..1c565086 --- /dev/null +++ b/src/features/formatters/ruff.ts @@ -0,0 +1,29 @@ +import { CancellationToken, FormattingOptions, OutputChannel, Range, TextDocument, TextEdit, Thenable, window } from 'coc.nvim'; +import { IPythonSettings } from '../../types'; +import { BaseFormatter } from './baseFormatter'; + +export class RuffFormatter extends BaseFormatter { + constructor(public readonly pythonSettings: IPythonSettings, public readonly outputChannel: OutputChannel) { + super('ruff', pythonSettings, outputChannel); + } + + public formatDocument(document: TextDocument, options: FormattingOptions, token: CancellationToken, range?: Range): Thenable { + const formatSelection = range ? range : false; + + if (formatSelection) { + const errorMessage = async () => { + this.outputChannel.appendLine('Ruff does not support the "Format Selection" command'); + window.showErrorMessage('Ruff does not support the "Format Selection" command'); + return [] as TextEdit[]; + }; + + return errorMessage(); + } + + const ruffArgs = ['format', '--diff', '--silent']; + if (this.pythonSettings.formatting.ruffArgs.length > 0) { + ruffArgs.push(...this.pythonSettings.formatting.ruffArgs); + } + return super.provideDocumentFormattingEdits(document, options, token, ruffArgs); + } +} diff --git a/src/features/formatting.ts b/src/features/formatting.ts index cde93fd3..350630cb 100644 --- a/src/features/formatting.ts +++ b/src/features/formatting.ts @@ -19,6 +19,7 @@ import { BlackFormatter } from './formatters/black'; import { BlackdFormatter } from './formatters/blackd'; import { DarkerFormatter } from './formatters/darker'; import { PyinkFormatter } from './formatters/pyink'; +import { RuffFormatter } from './formatters/ruff'; import { YapfFormatter } from './formatters/yapf'; export class PythonFormattingEditProvider implements DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider { @@ -45,6 +46,9 @@ export class PythonFormattingEditProvider implements DocumentFormattingEditProvi case 'yapf': this.formatters.set('yapf', new YapfFormatter(this.pythonSettings, this.outputChannel)); break; + case 'ruff': + this.formatters.set('ruff', new RuffFormatter(this.pythonSettings, this.outputChannel)); + break; case 'autopep8': this.formatters.set('autopep8', new AutoPep8Formatter(this.pythonSettings, this.outputChannel)); break; diff --git a/src/types.ts b/src/types.ts index 25168459..ba4a99b8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -47,7 +47,7 @@ export enum Product { } export type LinterId = 'bandit' | 'flake8' | 'mypy' | 'ruff' | 'pycodestyle' | 'prospector' | 'pydocstyle' | 'pyflakes' | 'pylama' | 'pylint' | 'pytype'; -export type FormatterId = 'yapf' | 'black' | 'autopep8' | 'darker' | 'blackd' | 'pyink'; +export type FormatterId = 'yapf' | 'black' | 'autopep8' | 'darker' | 'blackd' | 'pyink' | 'ruff'; export type TestingFramework = 'unittest' | 'pytest'; export interface ILinterInfo { @@ -158,6 +158,8 @@ export interface IFormattingSettings { readonly pyinkArgs: string[]; yapfPath: string; readonly yapfArgs: string[]; + ruffPath: string; + readonly ruffArgs: string[]; darkerPath: string; readonly darkerArgs: string[]; blackdPath: string;