mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:18 +00:00
Fix non‑BMP code point handling in quick‑fixes and markers (#20526)
Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
parent
09f570af92
commit
3e1e02e9b6
4 changed files with 70 additions and 33 deletions
|
@ -19,7 +19,7 @@ There are multiple versions for the different wasm-pack targets. See [here](http
|
||||||
This example uses the wasm-pack web target and is known to work with Vite.
|
This example uses the wasm-pack web target and is known to work with Vite.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import init, { Workspace, type Diagnostic } from '@astral-sh/ruff-wasm-web';
|
import init, { Workspace, type Diagnostic, PositionEncoding } from '@astral-sh/ruff-wasm-web';
|
||||||
|
|
||||||
const exampleDocument = `print('hello'); print("world")`
|
const exampleDocument = `print('hello'); print("world")`
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ const workspace = new Workspace({
|
||||||
'F'
|
'F'
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
}, PositionEncoding.UTF16);
|
||||||
|
|
||||||
// Will contain 1 diagnostic code for E702: Multiple statements on one line
|
// Will contain 1 diagnostic code for E702: Multiple statements on one line
|
||||||
const diagnostics: Diagnostic[] = workspace.check(exampleDocument);
|
const diagnostics: Diagnostic[] = workspace.check(exampleDocument);
|
||||||
|
|
|
@ -19,7 +19,7 @@ use ruff_python_formatter::{PyFormatContext, QuoteStyle, format_module_ast, pret
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_python_parser::{Mode, ParseOptions, Parsed, parse, parse_unchecked};
|
use ruff_python_parser::{Mode, ParseOptions, Parsed, parse, parse_unchecked};
|
||||||
use ruff_python_trivia::CommentRanges;
|
use ruff_python_trivia::CommentRanges;
|
||||||
use ruff_source_file::{LineColumn, OneIndexed};
|
use ruff_source_file::{OneIndexed, PositionEncoding as SourcePositionEncoding, SourceLocation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
use ruff_workspace::Settings;
|
use ruff_workspace::Settings;
|
||||||
use ruff_workspace::configuration::Configuration;
|
use ruff_workspace::configuration::Configuration;
|
||||||
|
@ -117,6 +117,7 @@ pub fn run() {
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
|
position_encoding: SourcePositionEncoding,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
@ -126,7 +127,7 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(constructor)]
|
#[wasm_bindgen(constructor)]
|
||||||
pub fn new(options: JsValue) -> Result<Workspace, Error> {
|
pub fn new(options: JsValue, position_encoding: PositionEncoding) -> Result<Workspace, Error> {
|
||||||
let options: Options = serde_wasm_bindgen::from_value(options).map_err(into_error)?;
|
let options: Options = serde_wasm_bindgen::from_value(options).map_err(into_error)?;
|
||||||
let configuration =
|
let configuration =
|
||||||
Configuration::from_options(options, Some(Path::new(".")), Path::new("."))
|
Configuration::from_options(options, Some(Path::new(".")), Path::new("."))
|
||||||
|
@ -135,7 +136,10 @@ impl Workspace {
|
||||||
.into_settings(Path::new("."))
|
.into_settings(Path::new("."))
|
||||||
.map_err(into_error)?;
|
.map_err(into_error)?;
|
||||||
|
|
||||||
Ok(Workspace { settings })
|
Ok(Workspace {
|
||||||
|
settings,
|
||||||
|
position_encoding: position_encoding.into(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = defaultSettings)]
|
#[wasm_bindgen(js_name = defaultSettings)]
|
||||||
|
@ -228,14 +232,16 @@ impl Workspace {
|
||||||
|
|
||||||
let messages: Vec<ExpandedMessage> = diagnostics
|
let messages: Vec<ExpandedMessage> = diagnostics
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|msg| ExpandedMessage {
|
.map(|msg| {
|
||||||
|
let range = msg.range().unwrap_or_default();
|
||||||
|
ExpandedMessage {
|
||||||
code: msg.secondary_code_or_id().to_string(),
|
code: msg.secondary_code_or_id().to_string(),
|
||||||
message: msg.body().to_string(),
|
message: msg.body().to_string(),
|
||||||
start_location: source_code
|
start_location: source_code
|
||||||
.line_column(msg.range().unwrap_or_default().start())
|
.source_location(range.start(), self.position_encoding)
|
||||||
.into(),
|
.into(),
|
||||||
end_location: source_code
|
end_location: source_code
|
||||||
.line_column(msg.range().unwrap_or_default().end())
|
.source_location(range.end(), self.position_encoding)
|
||||||
.into(),
|
.into(),
|
||||||
fix: msg.fix().map(|fix| ExpandedFix {
|
fix: msg.fix().map(|fix| ExpandedFix {
|
||||||
message: msg.first_help_text().map(ToString::to_string),
|
message: msg.first_help_text().map(ToString::to_string),
|
||||||
|
@ -243,12 +249,17 @@ impl Workspace {
|
||||||
.edits()
|
.edits()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|edit| ExpandedEdit {
|
.map(|edit| ExpandedEdit {
|
||||||
location: source_code.line_column(edit.start()).into(),
|
location: source_code
|
||||||
end_location: source_code.line_column(edit.end()).into(),
|
.source_location(edit.start(), self.position_encoding)
|
||||||
|
.into(),
|
||||||
|
end_location: source_code
|
||||||
|
.source_location(edit.end(), self.position_encoding)
|
||||||
|
.into(),
|
||||||
content: edit.content().map(ToString::to_string),
|
content: edit.content().map(ToString::to_string),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}),
|
}),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -331,14 +342,37 @@ impl<'a> ParsedModule<'a> {
|
||||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
|
#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
|
||||||
pub struct Location {
|
pub struct Location {
|
||||||
pub row: OneIndexed,
|
pub row: OneIndexed,
|
||||||
|
/// The character offset from the start of the line.
|
||||||
|
///
|
||||||
|
/// The semantic of the offset depends on the [`PositionEncoding`] used when creating
|
||||||
|
/// the [`Workspace`].
|
||||||
pub column: OneIndexed,
|
pub column: OneIndexed,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<LineColumn> for Location {
|
impl From<SourceLocation> for Location {
|
||||||
fn from(value: LineColumn) -> Self {
|
fn from(value: SourceLocation) -> Self {
|
||||||
Self {
|
Self {
|
||||||
row: value.line,
|
row: value.line,
|
||||||
column: value.column,
|
column: value.character_offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Copy, Clone)]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub enum PositionEncoding {
|
||||||
|
#[default]
|
||||||
|
Utf8,
|
||||||
|
Utf16,
|
||||||
|
Utf32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PositionEncoding> for SourcePositionEncoding {
|
||||||
|
fn from(value: PositionEncoding) -> Self {
|
||||||
|
match value {
|
||||||
|
PositionEncoding::Utf8 => Self::Utf8,
|
||||||
|
PositionEncoding::Utf16 => Self::Utf16,
|
||||||
|
PositionEncoding::Utf32 => Self::Utf32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,15 @@ use wasm_bindgen_test::wasm_bindgen_test;
|
||||||
|
|
||||||
use ruff_linter::registry::Rule;
|
use ruff_linter::registry::Rule;
|
||||||
use ruff_source_file::OneIndexed;
|
use ruff_source_file::OneIndexed;
|
||||||
use ruff_wasm::{ExpandedMessage, Location, Workspace};
|
use ruff_wasm::{ExpandedMessage, Location, PositionEncoding, Workspace};
|
||||||
|
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
($source:expr, $config:expr, $expected:expr) => {{
|
($source:expr, $config:expr, $expected:expr) => {{
|
||||||
let config = js_sys::JSON::parse($config).unwrap();
|
let config = js_sys::JSON::parse($config).unwrap();
|
||||||
match Workspace::new(config).unwrap().check($source) {
|
match Workspace::new(config, PositionEncoding::Utf8)
|
||||||
|
.unwrap()
|
||||||
|
.check($source)
|
||||||
|
{
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
let result: Vec<ExpandedMessage> = serde_wasm_bindgen::from_value(output).unwrap();
|
let result: Vec<ExpandedMessage> = serde_wasm_bindgen::from_value(output).unwrap();
|
||||||
assert_eq!(result, $expected);
|
assert_eq!(result, $expected);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { Panel, PanelGroup } from "react-resizable-panels";
|
import { Panel, PanelGroup } from "react-resizable-panels";
|
||||||
import { Diagnostic, Workspace } from "ruff_wasm";
|
import { Diagnostic, Workspace, PositionEncoding } from "ruff_wasm";
|
||||||
import {
|
import {
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -173,7 +173,7 @@ export default function Editor({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const config = JSON.parse(settingsSource);
|
const config = JSON.parse(settingsSource);
|
||||||
const workspace = new Workspace(config);
|
const workspace = new Workspace(config, PositionEncoding.Utf16);
|
||||||
const diagnostics = workspace.check(pythonSource);
|
const diagnostics = workspace.check(pythonSource);
|
||||||
|
|
||||||
let secondary: SecondaryPanelResult = null;
|
let secondary: SecondaryPanelResult = null;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue