simdref 0.0.9__tar.gz → 0.0.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {simdref-0.0.9/src/simdref.egg-info → simdref-0.0.10}/PKG-INFO +1 -1
  2. {simdref-0.0.9 → simdref-0.0.10}/pyproject.toml +1 -1
  3. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/lsp.py +48 -13
  4. {simdref-0.0.9 → simdref-0.0.10/src/simdref.egg-info}/PKG-INFO +1 -1
  5. {simdref-0.0.9 → simdref-0.0.10}/tests/test_lsp_stdio.py +22 -0
  6. {simdref-0.0.9 → simdref-0.0.10}/LICENSE +0 -0
  7. {simdref-0.0.9 → simdref-0.0.10}/README.md +0 -0
  8. {simdref-0.0.9 → simdref-0.0.10}/setup.cfg +0 -0
  9. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/__init__.py +0 -0
  10. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/__main__.py +0 -0
  11. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/annotate.py +0 -0
  12. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/arm_instructions.py +0 -0
  13. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/cli.py +0 -0
  14. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/display.py +0 -0
  15. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/export.py +0 -0
  16. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/filters.py +0 -0
  17. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/ingest.py +0 -0
  18. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/ingest_catalog.py +0 -0
  19. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/ingest_pdf.py +0 -0
  20. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/ingest_sources.py +0 -0
  21. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/manpages.py +0 -0
  22. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/models.py +0 -0
  23. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/pdfparse/__init__.py +0 -0
  24. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/pdfparse/base.py +0 -0
  25. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/pdfparse/intel.py +0 -0
  26. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/pdfparse/registry.py +0 -0
  27. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/pdfparse/types.py +0 -0
  28. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/pdfrefs.py +0 -0
  29. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/perf.py +0 -0
  30. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/perf_sources/__init__.py +0 -0
  31. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/perf_sources/cores.py +0 -0
  32. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/perf_sources/llvm_mca.py +0 -0
  33. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/perf_sources/llvm_scheduling.py +0 -0
  34. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/perf_sources/merge.py +0 -0
  35. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/queries.py +0 -0
  36. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/riscv.py +0 -0
  37. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/search.py +0 -0
  38. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/storage.py +0 -0
  39. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/tui.py +0 -0
  40. {simdref-0.0.9 → simdref-0.0.10}/src/simdref/ui_labels.py +0 -0
  41. {simdref-0.0.9 → simdref-0.0.10}/src/simdref.egg-info/SOURCES.txt +0 -0
  42. {simdref-0.0.9 → simdref-0.0.10}/src/simdref.egg-info/dependency_links.txt +0 -0
  43. {simdref-0.0.9 → simdref-0.0.10}/src/simdref.egg-info/entry_points.txt +0 -0
  44. {simdref-0.0.9 → simdref-0.0.10}/src/simdref.egg-info/requires.txt +0 -0
  45. {simdref-0.0.9 → simdref-0.0.10}/src/simdref.egg-info/top_level.txt +0 -0
  46. {simdref-0.0.9 → simdref-0.0.10}/tests/test_annotate.py +0 -0
  47. {simdref-0.0.9 → simdref-0.0.10}/tests/test_annotate_positions.py +0 -0
  48. {simdref-0.0.9 → simdref-0.0.10}/tests/test_audit_coverage.py +0 -0
  49. {simdref-0.0.9 → simdref-0.0.10}/tests/test_auto_update_on_version_change.py +0 -0
  50. {simdref-0.0.9 → simdref-0.0.10}/tests/test_cli_bare_query.py +0 -0
  51. {simdref-0.0.9 → simdref-0.0.10}/tests/test_cli_bootstrap_progress.py +0 -0
  52. {simdref-0.0.9 → simdref-0.0.10}/tests/test_cli_help.py +0 -0
  53. {simdref-0.0.9 → simdref-0.0.10}/tests/test_cli_llm.py +0 -0
  54. {simdref-0.0.9 → simdref-0.0.10}/tests/test_coverage_live.py +0 -0
  55. {simdref-0.0.9 → simdref-0.0.10}/tests/test_coverage_parity.py +0 -0
  56. {simdref-0.0.9 → simdref-0.0.10}/tests/test_display.py +0 -0
  57. {simdref-0.0.9 → simdref-0.0.10}/tests/test_export.py +0 -0
  58. {simdref-0.0.9 → simdref-0.0.10}/tests/test_filters.py +0 -0
  59. {simdref-0.0.9 → simdref-0.0.10}/tests/test_ingest_sources.py +0 -0
  60. {simdref-0.0.9 → simdref-0.0.10}/tests/test_intel_operation_and_url.py +0 -0
  61. {simdref-0.0.9 → simdref-0.0.10}/tests/test_issue2_fixes.py +0 -0
  62. {simdref-0.0.9 → simdref-0.0.10}/tests/test_issues_23_24_25.py +0 -0
  63. {simdref-0.0.9 → simdref-0.0.10}/tests/test_lsp_web.py +0 -0
  64. {simdref-0.0.9 → simdref-0.0.10}/tests/test_models.py +0 -0
  65. {simdref-0.0.9 → simdref-0.0.10}/tests/test_pdfparse.py +0 -0
  66. {simdref-0.0.9 → simdref-0.0.10}/tests/test_perf.py +0 -0
  67. {simdref-0.0.9 → simdref-0.0.10}/tests/test_perf_sources.py +0 -0
  68. {simdref-0.0.9 → simdref-0.0.10}/tests/test_presentation.py +0 -0
  69. {simdref-0.0.9 → simdref-0.0.10}/tests/test_preset_persistence.py +0 -0
  70. {simdref-0.0.9 → simdref-0.0.10}/tests/test_riscv_docs_pages.py +0 -0
  71. {simdref-0.0.9 → simdref-0.0.10}/tests/test_search.py +0 -0
  72. {simdref-0.0.9 → simdref-0.0.10}/tests/test_search_pushdown.py +0 -0
  73. {simdref-0.0.9 → simdref-0.0.10}/tests/test_source_kind_filter.py +0 -0
  74. {simdref-0.0.9 → simdref-0.0.10}/tests/test_source_validation.py +0 -0
  75. {simdref-0.0.9 → simdref-0.0.10}/tests/test_storage_payload.py +0 -0
  76. {simdref-0.0.9 → simdref-0.0.10}/tests/test_storage_schema.py +0 -0
  77. {simdref-0.0.9 → simdref-0.0.10}/tests/test_tui.py +0 -0
  78. {simdref-0.0.9 → simdref-0.0.10}/tests/test_ui_labels_parity.py +0 -0
  79. {simdref-0.0.9 → simdref-0.0.10}/tests/test_version_matches_pyproject.py +0 -0
  80. {simdref-0.0.9 → simdref-0.0.10}/tests/test_x86_linking.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simdref
3
- Version: 0.0.9
3
+ Version: 0.0.10
4
4
  Summary: Searchable SIMD intrinsic and instruction reference with CLI, manpages, TUI, and LSP.
5
5
  Author: Marco
6
6
  License: GPL-3.0-or-later
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simdref"
7
- version = "0.0.9"
7
+ version = "0.0.10"
8
8
  description = "Searchable SIMD intrinsic and instruction reference with CLI, manpages, TUI, and LSP."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -216,6 +216,43 @@ def _is_c_doc(language_id: str, uri: str) -> bool:
216
216
  return language_id in ("c", "cpp") or uri.lower().endswith(C_EXTENSIONS)
217
217
 
218
218
 
219
+ def _semicolon_is_comment(language_id: str, uri: str) -> bool:
220
+ # A .s/.S extension means GAS syntax: ";" stays a statement separator there
221
+ # even if the client tags the buffer with an assembly languageId.
222
+ if _is_c_doc(language_id, uri):
223
+ return False
224
+ if uri.lower().endswith(".s"):
225
+ return False
226
+ return language_id in ("asm", "nasm", "masm") or uri.lower().endswith((".asm", ".nasm"))
227
+
228
+
229
+ def _asm_line_at(text: str, language_id: str, uri: str, offset: int) -> str | None:
230
+ """Return the assembler segment that holds the text offset, or None.
231
+
232
+ C/C++ documents hold assembler in string literals in asm(...) calls, so the
233
+ segment comes from _asm_literals. In every other document the whole source
234
+ line is the segment. Hover and inlay hints must call this one function so
235
+ both parse the same text.
236
+ """
237
+ if _is_c_doc(language_id, uri):
238
+ spaced = text.replace("\\t", " ")
239
+ for start, body in _asm_literals(spaced):
240
+ if start <= offset <= start + len(body):
241
+ cut = 0
242
+ for split in ASM_SPLIT_RE.finditer(body):
243
+ if cut <= offset - start < split.start():
244
+ return body[cut : split.start()]
245
+ cut = split.end()
246
+ return body[cut:]
247
+ return None
248
+ lines = text.split("\n")
249
+ for line, source_line in enumerate(lines):
250
+ end = offset - sum(len(item) + 1 for item in lines[:line])
251
+ if 0 <= end <= len(source_line):
252
+ return source_line
253
+ return None
254
+
255
+
219
256
  def _asm_literals(text: str) -> list[tuple[int, str]]:
220
257
  """Return (offset, body) for each string literal inside an asm(...) call in C source."""
221
258
  masked = C_TOKEN_RE.sub(
@@ -303,13 +340,7 @@ def _inlay_hints(conn, text: str, language_id: str, uri: str, start: int, end: i
303
340
  db_path = conn.execute("PRAGMA database_list").fetchone()[2]
304
341
  source_lines = [line.rstrip("\r") for line in text.split("\n")]
305
342
  is_c_doc = _is_c_doc(language_id, uri)
306
- # A .s/.S extension means GAS syntax: ";" stays a statement separator there
307
- # even if the client tags the buffer with an assembly languageId.
308
- semicolon_is_comment = (
309
- not is_c_doc
310
- and not uri.lower().endswith(".s")
311
- and (language_id in ("asm", "nasm", "masm") or uri.lower().endswith((".asm", ".nasm")))
312
- )
343
+ semicolon_is_comment = _semicolon_is_comment(language_id, uri)
313
344
  if is_c_doc:
314
345
  candidates = [
315
346
  (text.count("\n", 0, offset), segment)
@@ -411,12 +442,16 @@ def main() -> int:
411
442
  operand_count = None
412
443
  operand_text = ""
413
444
  if word and allow_instruction:
414
- source_lines = text.split("\n")
415
- source_line = source_lines[line] if line < len(source_lines) else ""
416
- operand_text = source_line
417
- parsed = _mnemonic_from_asm_line(source_line)
418
- if parsed and parsed[0].casefold() == word.casefold():
419
- operand_count = parsed[1]
445
+ offset = sum(len(item) + 1 for item in text.split("\n")[:line]) + character
446
+ language_id = session.languages.get(uri, "")
447
+ segment = _asm_line_at(text, language_id, uri, offset)
448
+ if segment:
449
+ operand_text = segment
450
+ parsed = _mnemonic_from_asm_line(
451
+ segment, _semicolon_is_comment(language_id, uri)
452
+ )
453
+ if parsed and parsed[0].casefold() == word.casefold():
454
+ operand_count = parsed[1]
420
455
  body = (
421
456
  _hover_markdown(
422
457
  conn,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simdref
3
- Version: 0.0.9
3
+ Version: 0.0.10
4
4
  Summary: Searchable SIMD intrinsic and instruction reference with CLI, manpages, TUI, and LSP.
5
5
  Author: Marco
6
6
  License: GPL-3.0-or-later
@@ -265,6 +265,28 @@ class LspEndToEndTests(unittest.TestCase):
265
265
  self.server.open("file:///tmp/x.hxx", "", "int x;\n")
266
266
  self.assertEqual(self.server.hints("file:///tmp/x.hxx"), []) # "int" is an x86 mnemonic
267
267
 
268
+ def test_cpp_hover_inside_asm_literal_matches_the_ymm_form(self):
269
+ text = 'asm volatile("vaddps %ymm2, %ymm1, %ymm0");\n'
270
+ self.server.open(CPP_URI, "cpp", text)
271
+ result = self.server.hover(CPP_URI, 0, 16)
272
+ self.assertIsNotNone(result, "hover on vaddps inside the asm literal returned null")
273
+ value = result["contents"]["value"]
274
+ self.assertIn("VADDPS (YMM, YMM, YMM)", value)
275
+ self.assertNotIn("VADDPS (XMM, K, XMM, M128)", value)
276
+
277
+ def test_asm_hover_and_hint_agree_on_semicolon_comment(self):
278
+ uri = "file:///tmp/simdref_lsp_test_hover.asm"
279
+ self.server.open(uri, "nasm", "adc eax, ebx ; j, k\n")
280
+ hint = self.server.hints(uri)[0]["label"]
281
+ result = self.server.hover(uri, 0, 1)
282
+ self.assertIsNotNone(result, "hover on adc returned null")
283
+ value = result["contents"]["value"]
284
+ # The hover must pick the same form as the hint on the same line. The
285
+ # 4-operand parse lands on an ARM adc page, the 2-operand parse on the
286
+ # x86 "Add With Carry." form the hint names.
287
+ self.assertIn("Add With Carry.", value)
288
+ self.assertEqual(hint, "Add With Carry.")
289
+
268
290
  def test_asm_semicolon_comment_in_dot_asm_file(self):
269
291
  uri = "file:///tmp/simdref_lsp_test.asm"
270
292
  self.server.open(uri, "nasm", "vaddps ymm0, ymm1, ymm2 ; add, then, more\n")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes