diff --git a/pylight/src/parser/ruff.rs b/pylight/src/parser/ruff.rs index 6d25b40..c1b7551 100644 --- a/pylight/src/parser/ruff.rs +++ b/pylight/src/parser/ruff.rs @@ -101,8 +101,8 @@ impl<'a> SymbolExtractor<'a> { let location = self .source_code .source_location(offset.into(), ruff_source_file::PositionEncoding::Utf8); - // Both line and column are 1-based in Ruff - (location.line.get(), location.character_offset.get()) + // Ruff returns 1-based line and column, but we need 0-based column for compatibility + (location.line.get(), location.character_offset.get() - 1) } } diff --git a/pylight/src/parser/tests.rs b/pylight/src/parser/tests.rs index 574c8ed..607d0de 100644 --- a/pylight/src/parser/tests.rs +++ b/pylight/src/parser/tests.rs @@ -125,4 +125,49 @@ class MyClass: .iter() .any(|s| s.name == "value" && s.kind == SymbolKind::Method)); } + + #[test] + fn test_column_positions() { + use crate::parser::{create_parser, ParserBackend}; + + // Test both parser backends + for backend in [ParserBackend::TreeSitter, ParserBackend::Ruff] { + let parser = create_parser(backend).unwrap(); + + // Test function column position + let code = "def my_func():\n pass"; + let symbols = parser.parse_file(Path::new("test.py"), code).unwrap(); + assert_eq!(symbols.len(), 1); + assert_eq!(symbols[0].name, "my_func"); + assert_eq!(symbols[0].line, 1); + assert_eq!( + symbols[0].column, 4, + "Function name should start at column 4 (0-based) for parser {:?}", + backend + ); + + // Test class column position + let code = "class MyClass:\n pass"; + let symbols = parser.parse_file(Path::new("test.py"), code).unwrap(); + assert_eq!(symbols.len(), 1); + assert_eq!(symbols[0].name, "MyClass"); + assert_eq!(symbols[0].line, 1); + assert_eq!( + symbols[0].column, 6, + "Class name should start at column 6 (0-based) for parser {:?}", + backend + ); + + // Test indented method column position + let code = "class MyClass:\n def my_method(self):\n pass"; + let symbols = parser.parse_file(Path::new("test.py"), code).unwrap(); + let method = symbols.iter().find(|s| s.name == "my_method").unwrap(); + assert_eq!(method.line, 2); + assert_eq!( + method.column, 8, + "Method name should start at column 8 (0-based) for parser {:?}", + backend + ); + } + } }