treesitter.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import warnings
  2. from grep_ast import TreeContext, filename_to_lang
  3. from grep_ast.parsers import PARSERS
  4. from tree_sitter_languages import get_parser
  5. from openhands.linter.base import BaseLinter, LintResult
  6. # tree_sitter is throwing a FutureWarning
  7. warnings.simplefilter('ignore', category=FutureWarning)
  8. def tree_context(fname, code, line_nums):
  9. context = TreeContext(
  10. fname,
  11. code,
  12. color=False,
  13. line_number=True,
  14. child_context=False,
  15. last_line=False,
  16. margin=0,
  17. mark_lois=True,
  18. loi_pad=3,
  19. # header_max=30,
  20. show_top_of_file_parent_scope=False,
  21. )
  22. line_nums = set(line_nums)
  23. context.add_lines_of_interest(line_nums)
  24. context.add_context()
  25. output = context.format()
  26. return output
  27. def traverse_tree(node):
  28. """Traverses the tree to find errors."""
  29. errors = []
  30. if node.type == 'ERROR' or node.is_missing:
  31. line_no = node.start_point[0] + 1
  32. col_no = node.start_point[1] + 1
  33. error_type = 'Missing node' if node.is_missing else 'Syntax error'
  34. errors.append((line_no, col_no, error_type))
  35. for child in node.children:
  36. errors += traverse_tree(child)
  37. return errors
  38. class TreesitterBasicLinter(BaseLinter):
  39. @property
  40. def supported_extensions(self) -> list[str]:
  41. return list(PARSERS.keys())
  42. def lint(self, file_path: str) -> list[LintResult]:
  43. """Use tree-sitter to look for syntax errors, display them with tree context."""
  44. lang = filename_to_lang(file_path)
  45. if not lang:
  46. return []
  47. parser = get_parser(lang)
  48. with open(file_path, 'r') as f:
  49. code = f.read()
  50. tree = parser.parse(bytes(code, 'utf-8'))
  51. errors = traverse_tree(tree.root_node)
  52. if not errors:
  53. return []
  54. return [
  55. LintResult(
  56. file=file_path,
  57. line=int(line),
  58. column=int(col),
  59. message=error_details,
  60. )
  61. for line, col, error_details in errors
  62. ]