tritonparse 0.2.1.dev20250918071513__tar.gz → 0.2.1.dev20250919071533__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.

Potentially problematic release.


This version of tritonparse might be problematic. Click here for more details.

Files changed (108) hide show
  1. {tritonparse-0.2.1.dev20250918071513/tritonparse.egg-info → tritonparse-0.2.1.dev20250919071533}/PKG-INFO +1 -1
  2. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533/tritonparse.egg-info}/PKG-INFO +1 -1
  3. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse.egg-info/SOURCES.txt +3 -0
  4. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/package-lock.json +2 -2
  5. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/package.json +1 -1
  6. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/App.tsx +144 -51
  7. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/CopyCodeButton.tsx +4 -4
  8. tritonparse-0.2.1.dev20250919071533/website/src/components/DiffComparisonView.tsx +207 -0
  9. tritonparse-0.2.1.dev20250919071533/website/src/context/FileDiffSession.tsx +132 -0
  10. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/main.tsx +4 -1
  11. tritonparse-0.2.1.dev20250919071533/website/src/pages/FileDiffView.tsx +645 -0
  12. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.ci/README.md +0 -0
  13. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.ci/install-project.sh +0 -0
  14. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.ci/install-triton-kernels.sh +0 -0
  15. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.ci/install-triton.sh +0 -0
  16. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.ci/run-tests.sh +0 -0
  17. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.ci/setup.sh +0 -0
  18. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.github/PAGES_SETUP.md +0 -0
  19. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.github/copilot-instructions.md +0 -0
  20. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.github/workflows/deploy-pages-standalone.yml +0 -0
  21. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.github/workflows/deploy-pages.yml +0 -0
  22. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.github/workflows/nightly-pypi.yml +0 -0
  23. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.github/workflows/test.yml +0 -0
  24. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/.gitignore +0 -0
  25. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/CHANGELOG.md +0 -0
  26. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/CODE_OF_CONDUCT.md +0 -0
  27. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/CONTRIBUTING.md +0 -0
  28. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/LICENSE +0 -0
  29. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/Makefile +0 -0
  30. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/README.md +0 -0
  31. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/__init__.py +0 -0
  32. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/docs/README.md +0 -0
  33. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/docs/screenshots/code-comparison.png +0 -0
  34. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/docs/screenshots/kernel-overview.png +0 -0
  35. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/pyproject.toml +0 -0
  36. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/run.py +0 -0
  37. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/setup.cfg +0 -0
  38. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/README.md +0 -0
  39. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/__init__.py +0 -0
  40. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/example_output/logs/dedicated_log_triton_trace_findhao_.ndjson +0 -0
  41. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/example_output/parsed_output/dedicated_log_triton_trace_findhao__mapped.ndjson.gz +0 -0
  42. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/example_output/parsed_output/f0_fc0_a0_cai-.ndjson.gz +0 -0
  43. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/example_output/parsed_output/log_file_list.json +0 -0
  44. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/example_output/parsed_output_complex/dedicated_log_triton_trace_findhao__mapped.ndjson.gz +0 -0
  45. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/example_output/parsed_output_complex/log_file_list.json +0 -0
  46. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/example_output/repro/repro_context_20250816192455.json +0 -0
  47. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/test_add.py +0 -0
  48. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tests/test_tritonparse.py +0 -0
  49. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/__init__.py +0 -0
  50. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/common.py +0 -0
  51. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/event_diff.py +0 -0
  52. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/extract_source_mappings.py +0 -0
  53. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/ir_parser.py +0 -0
  54. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/mapper.py +0 -0
  55. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/reproducer/__init__.py +0 -0
  56. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/reproducer/utils.py +0 -0
  57. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/shared_vars.py +0 -0
  58. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/source_type.py +0 -0
  59. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/sourcemap_utils.py +0 -0
  60. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/structured_logging.py +0 -0
  61. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/tools/__init__.py +0 -0
  62. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/tools/decompress_bin_ndjson.py +0 -0
  63. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/tools/format_fix.py +0 -0
  64. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/tools/load_tensor.py +0 -0
  65. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/tools/prettify_ndjson.py +0 -0
  66. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/tools/readme.md +0 -0
  67. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/tp_logger.py +0 -0
  68. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/trace_processor.py +0 -0
  69. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse/utils.py +0 -0
  70. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse.egg-info/dependency_links.txt +0 -0
  71. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse.egg-info/requires.txt +0 -0
  72. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/tritonparse.egg-info/top_level.txt +0 -0
  73. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/eslint.config.js +0 -0
  74. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/index.html +0 -0
  75. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/postcss.config.js +0 -0
  76. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/public/dedicated_log_triton_trace_findhao__mapped.ndjson.gz +0 -0
  77. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/public/f0_fc0_a0_cai-.ndjson +0 -0
  78. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/public/favicon.ico +0 -0
  79. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/public/logo.svg +0 -0
  80. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/scripts/inline-html.js +0 -0
  81. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/App.css +0 -0
  82. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/assets/react.svg +0 -0
  83. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/ArgumentViewer.tsx +0 -0
  84. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/Callstack.tsx +0 -0
  85. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/CodeComparisonView.tsx +0 -0
  86. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/CodeViewer.tsx +0 -0
  87. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/CompilationInfo.tsx +0 -0
  88. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/DataSourceSelector.tsx +0 -0
  89. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/DiffViewer.tsx +0 -0
  90. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/ExternalLink.tsx +0 -0
  91. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/SingleCodeViewer.tsx +0 -0
  92. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/StackDiffViewer.tsx +0 -0
  93. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/ToggleSwitch.tsx +0 -0
  94. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/TritonIRs.tsx +0 -0
  95. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/components/WelcomeScreen.tsx +0 -0
  96. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/index.css +0 -0
  97. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/pages/CodeView.tsx +0 -0
  98. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/pages/KernelOverview.tsx +0 -0
  99. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/utils/dataLoader.ts +0 -0
  100. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/utils/fbDetection.ts +0 -0
  101. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/utils/safeImport.ts +0 -0
  102. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/utils/tensor.ts +0 -0
  103. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/src/vite-env.d.ts +0 -0
  104. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/tailwind.config.js +0 -0
  105. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/tsconfig.app.json +0 -0
  106. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/tsconfig.json +0 -0
  107. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/tsconfig.node.json +0 -0
  108. {tritonparse-0.2.1.dev20250918071513 → tritonparse-0.2.1.dev20250919071533}/website/vite.config.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tritonparse
3
- Version: 0.2.1.dev20250918071513
3
+ Version: 0.2.1.dev20250919071533
4
4
  Summary: TritonParse: A Compiler Tracer, Visualizer, and mini-Reproducer Generator for Triton Kernels
5
5
  Author-email: Yueming Hao <yhao@meta.com>
6
6
  License-Expression: BSD-3-Clause
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tritonparse
3
- Version: 0.2.1.dev20250918071513
3
+ Version: 0.2.1.dev20250919071533
4
4
  Summary: TritonParse: A Compiler Tracer, Visualizer, and mini-Reproducer Generator for Triton Kernels
5
5
  Author-email: Yueming Hao <yhao@meta.com>
6
6
  License-Expression: BSD-3-Clause
@@ -88,6 +88,7 @@ website/src/components/CodeViewer.tsx
88
88
  website/src/components/CompilationInfo.tsx
89
89
  website/src/components/CopyCodeButton.tsx
90
90
  website/src/components/DataSourceSelector.tsx
91
+ website/src/components/DiffComparisonView.tsx
91
92
  website/src/components/DiffViewer.tsx
92
93
  website/src/components/ExternalLink.tsx
93
94
  website/src/components/SingleCodeViewer.tsx
@@ -95,7 +96,9 @@ website/src/components/StackDiffViewer.tsx
95
96
  website/src/components/ToggleSwitch.tsx
96
97
  website/src/components/TritonIRs.tsx
97
98
  website/src/components/WelcomeScreen.tsx
99
+ website/src/context/FileDiffSession.tsx
98
100
  website/src/pages/CodeView.tsx
101
+ website/src/pages/FileDiffView.tsx
99
102
  website/src/pages/KernelOverview.tsx
100
103
  website/src/utils/dataLoader.ts
101
104
  website/src/utils/fbDetection.ts
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "tritonparse-website",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "tritonparse-website",
9
- "version": "0.2.0",
9
+ "version": "0.2.3",
10
10
  "dependencies": {
11
11
  "@monaco-editor/react": "^4.7.0",
12
12
  "@types/react-syntax-highlighter": "^15.5.7",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tritonparse-website",
3
3
  "private": true,
4
- "version": "0.2.0",
4
+ "version": "0.2.3",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -9,18 +9,21 @@ import {
9
9
  } from "./utils/dataLoader";
10
10
  import { checkFbDirectoryExists } from "./utils/fbDetection";
11
11
  import CodeView from "./pages/CodeView";
12
+ import FileDiffView from "./pages/FileDiffView";
12
13
  import SingleCodeViewer from "./components/SingleCodeViewer";
13
14
  import KernelOverview from "./pages/KernelOverview";
14
15
  import DataSourceSelector from "./components/DataSourceSelector";
15
16
  import WelcomeScreen from "./components/WelcomeScreen";
16
17
  import ExternalLink from "./components/ExternalLink";
17
18
  import { mapLanguageToHighlighter } from "./components/CodeViewer";
19
+ import { useFileDiffSession } from "./context/FileDiffSession";
18
20
 
19
21
  /**
20
22
  * Main application component that handles data loading,
21
23
  * state management, and rendering different views.
22
24
  */
23
25
  function App() {
26
+ const sess = useFileDiffSession();
24
27
  // Store processed kernel data from log file
25
28
  const [kernels, setKernels] = useState<ProcessedKernel[]>([]);
26
29
  // Track loading state for displaying loading indicator
@@ -67,6 +70,9 @@ function App() {
67
70
  const newUrl = new URL(window.location.href);
68
71
  newUrl.searchParams.set("json_url", jsonUrl);
69
72
  window.history.replaceState({}, "", newUrl.toString());
73
+ } else if (view === "file_diff") {
74
+ // Allow direct navigation to File Diff even without json_url
75
+ setActiveTab("file_diff");
70
76
  }
71
77
 
72
78
  // Check if fb directory exists and load internal utils if available
@@ -129,6 +135,8 @@ function App() {
129
135
  // Then, determine which view to show
130
136
  if (view === "ir_code_comparison") {
131
137
  setActiveTab("comparison");
138
+ } else if (view === "file_diff") {
139
+ setActiveTab("file_diff");
132
140
  }
133
141
 
134
142
  setDataLoaded(true);
@@ -198,6 +206,8 @@ function App() {
198
206
  // Then, determine which view to show
199
207
  if (initialView === "ir_code_comparison") {
200
208
  setActiveTab("comparison");
209
+ } else if (initialView === "file_diff") {
210
+ setActiveTab("file_diff");
201
211
  }
202
212
  setDataLoaded(true);
203
213
  setLoadedUrl(url);
@@ -209,6 +219,8 @@ function App() {
209
219
  // Add view and kernel_hash parameters if applicable
210
220
  if (initialView === "ir_code_comparison") {
211
221
  newUrl.searchParams.set("view", "ir_code_comparison");
222
+ } else if (initialView === "file_diff") {
223
+ newUrl.searchParams.set("view", "file_diff");
212
224
  }
213
225
 
214
226
  if (kernelHash) {
@@ -278,6 +290,20 @@ function App() {
278
290
  }
279
291
  };
280
292
 
293
+ // Register app controls for FileDiffSession navigation
294
+ useEffect(() => {
295
+ sess.registerAppControls({
296
+ setActiveTab,
297
+ });
298
+ }, [sess, setActiveTab]);
299
+
300
+ // Clear FileDiff preview when entering/returning to File Diff to avoid preview intercepting other views
301
+ useEffect(() => {
302
+ if (activeTab === 'file_diff' && sess.preview.active) {
303
+ sess.clearPreview();
304
+ }
305
+ }, [activeTab, sess]);
306
+
281
307
  // Show loading indicator while data is being fetched
282
308
  if (loading) {
283
309
  return (
@@ -323,8 +349,45 @@ function App() {
323
349
  onBack={handleBackFromIRView}
324
350
  />
325
351
  );
352
+ } else if (sess.preview.active) {
353
+ const side = sess.preview.side === 'left' ? sess.left : sess.right;
354
+ const idx = side.selectedIdx ?? 0;
355
+ const kernelsSrc = side.kernels ?? [];
356
+ if (!kernelsSrc || kernelsSrc.length === 0) {
357
+ return <div className="text-red-600">Error: Preview kernel data not available.</div>;
358
+ }
359
+ if (sess.preview.view === 'overview') {
360
+ return (
361
+ <KernelOverview
362
+ key={`preview-overview-${sess.preview.side}-${idx}`}
363
+ kernels={kernelsSrc}
364
+ onViewIR={handleViewSingleIR}
365
+ selectedKernel={idx}
366
+ onSelectKernel={() => {}}
367
+ />
368
+ );
369
+ }
370
+ if (sess.preview.view === 'ir') {
371
+ return (
372
+ <CodeView
373
+ key={`preview-ir-${sess.preview.side}-${idx}`}
374
+ kernels={kernelsSrc}
375
+ selectedKernel={idx}
376
+ />
377
+ );
378
+ }
379
+ return null;
326
380
  } else if (!dataLoaded) {
327
- // Show welcome screen if no data is loaded
381
+ // Show welcome screen if no data is loaded, but allow File Diff tab to render its view when selected
382
+ if (activeTab === 'file_diff') {
383
+ return (
384
+ <FileDiffView
385
+ kernelsLeft={kernels}
386
+ selectedLeftIndex={Math.max(0, selectedKernel)}
387
+ leftLoadedUrl={loadedUrl}
388
+ />
389
+ );
390
+ }
328
391
  return (
329
392
  <WelcomeScreen
330
393
  loadDefaultData={loadDefaultData}
@@ -346,17 +409,36 @@ function App() {
346
409
  </div>
347
410
  );
348
411
  } else {
349
- // Show either overview or code comparison based on active tab
350
- return activeTab === "overview" ? (
351
- <KernelOverview
352
- kernels={kernels}
353
- onViewIR={handleViewSingleIR}
354
- selectedKernel={selectedKernel}
355
- onSelectKernel={handleSelectKernel}
356
- />
357
- ) : (
358
- <CodeView kernels={kernels} selectedKernel={selectedKernel} />
359
- );
412
+ // Show either overview, IR code, or file diff based on active tab
413
+ if (activeTab === "overview") {
414
+ return (
415
+ <KernelOverview
416
+ kernels={kernels}
417
+ onViewIR={handleViewSingleIR}
418
+ selectedKernel={selectedKernel}
419
+ onSelectKernel={handleSelectKernel}
420
+ />
421
+ );
422
+ }
423
+ if (activeTab === "comparison") {
424
+ return (
425
+ <CodeView
426
+ key={`codeview-main-${selectedKernel}`}
427
+ kernels={kernels}
428
+ selectedKernel={selectedKernel}
429
+ />
430
+ );
431
+ }
432
+ if (activeTab === "file_diff") {
433
+ return (
434
+ <FileDiffView
435
+ kernelsLeft={kernels}
436
+ selectedLeftIndex={Math.max(0, selectedKernel)}
437
+ leftLoadedUrl={loadedUrl}
438
+ />
439
+ );
440
+ }
441
+ return null;
360
442
  }
361
443
  };
362
444
 
@@ -430,45 +512,56 @@ function App() {
430
512
  isLoading={loading}
431
513
  />
432
514
 
433
- {/* Tab navigation (only show when data is loaded and not in IR view) */}
434
- {dataLoaded && kernels.length > 0 && !selectedIR && (
435
- <div className="flex space-x-4">
436
- <button
437
- className={`px-3 py-2 text-sm font-medium rounded-md ${activeTab === "overview" ? "bg-blue-700 text-white shadow-md" : "bg-blue-100 text-blue-700 hover:bg-blue-200"
438
- }`}
439
- onClick={() => {
440
- setActiveTab("overview");
441
-
442
- // Update URL parameters when switching to overview
443
- if (loadedUrl) {
444
- const newUrl = new URL(window.location.href);
445
- // Remove view parameter but keep kernel_hash
446
- newUrl.searchParams.delete("view");
447
- window.history.replaceState({}, "", newUrl.toString());
448
- }
449
- }}
450
- >
451
- Kernel Overview
452
- </button>
453
- <button
454
- className={`px-3 py-2 text-sm font-medium rounded-md ${activeTab === "comparison" ? "bg-blue-700 text-white shadow-md" : "bg-blue-100 text-blue-700 hover:bg-blue-200"
455
- }`}
456
- onClick={() => {
457
- setActiveTab("comparison");
458
-
459
- // Update URL parameters when switching to comparison view
460
- if (loadedUrl) {
461
- const newUrl = new URL(window.location.href);
462
- // Add view parameter
463
- newUrl.searchParams.set("view", "ir_code_comparison");
464
- window.history.replaceState({}, "", newUrl.toString());
465
- }
466
- }}
467
- >
468
- IR Code Comparison
469
- </button>
470
- </div>
471
- )}
515
+ {/* Tab navigation: File Diff button placed as the last (rightmost) button */}
516
+ <div className="flex space-x-4">
517
+ {dataLoaded && kernels.length > 0 && !selectedIR && (
518
+ <>
519
+ <button
520
+ className={`px-3 py-2 text-sm font-medium rounded-md ${activeTab === "overview" ? "bg-blue-700 text-white shadow-md" : "bg-blue-100 text-blue-700 hover:bg-blue-200"
521
+ }`}
522
+ onClick={() => {
523
+ if (sess.preview?.active) sess.clearPreview();
524
+ setActiveTab("overview");
525
+
526
+ if (loadedUrl) {
527
+ const newUrl = new URL(window.location.href);
528
+ newUrl.searchParams.delete("view");
529
+ window.history.replaceState({}, "", newUrl.toString());
530
+ }
531
+ }}
532
+ >
533
+ Kernel Overview
534
+ </button>
535
+ <button
536
+ className={`px-3 py-2 text-sm font-medium rounded-md ${activeTab === "comparison" ? "bg-blue-700 text-white shadow-md" : "bg-blue-100 text-blue-700 hover:bg-blue-200"
537
+ }`}
538
+ onClick={() => {
539
+ if (sess.preview?.active) sess.clearPreview();
540
+ setActiveTab("comparison");
541
+
542
+ if (loadedUrl) {
543
+ const newUrl = new URL(window.location.href);
544
+ newUrl.searchParams.set("view", "ir_code_comparison");
545
+ window.history.replaceState({}, "", newUrl.toString());
546
+ }
547
+ }}
548
+ >
549
+ IR Code
550
+ </button>
551
+ </>
552
+ )}
553
+
554
+ <button
555
+ className={`px-3 py-2 text-sm font-medium rounded-md ${activeTab === "file_diff" ? "bg-blue-700 text-white shadow-md" : "bg-blue-100 text-blue-700 hover:bg-blue-200"
556
+ }`}
557
+ onClick={() => {
558
+ if (sess.preview?.active) sess.clearPreview();
559
+ setActiveTab("file_diff");
560
+ }}
561
+ >
562
+ File Diff
563
+ </button>
564
+ </div>
472
565
  </div>
473
566
  </div>
474
567
  </header>
@@ -41,15 +41,15 @@ const CopyCodeButton: React.FC<CopyCodeButtonProps> = ({
41
41
  // https://heroicons.com/
42
42
  <span>
43
43
  {/* Checkmark SVG icon */}
44
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" className="size-5">
45
- <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" />
44
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="size-5">
45
+ <path strokeLinecap="round" strokeLinejoin="round" d="m4.5 12.75 6 6 9-13.5" />
46
46
  </svg>
47
47
  </span>
48
48
  ) : (
49
49
  <span>
50
50
  {/* Clipboard copy icon */}
51
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" className="size-5">
52
- <path stroke-linecap="round" stroke-linejoin="round" d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0 0 15 2.25h-1.5a2.251 2.251 0 0 0-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9Z" />
51
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="size-5">
52
+ <path strokeLinecap="round" strokeLinejoin="round" d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0 0 15 2.25h-1.5a2.251 2.251 0 0 0-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9Z" />
53
53
  </svg>
54
54
  </span>
55
55
  )}
@@ -0,0 +1,207 @@
1
+ import React, { useEffect, useMemo, useRef, useState } from "react";
2
+ import { DiffEditor } from "@monaco-editor/react";
3
+
4
+ interface DiffOptions {
5
+ ignoreWhitespace?: boolean;
6
+ wordLevel?: boolean; // kept for future, Monaco uses its own algorithm
7
+ context?: number; // lines of context when hiding unchanged regions
8
+ wordWrap?: "off" | "on";
9
+ onlyChanged?: boolean;
10
+ }
11
+
12
+ interface DiffComparisonViewProps {
13
+ leftContent: string;
14
+ rightContent: string;
15
+ language?: string;
16
+ height?: string;
17
+ options?: DiffOptions;
18
+ }
19
+
20
+ const DiffComparisonView: React.FC<DiffComparisonViewProps> = ({
21
+ leftContent,
22
+ rightContent,
23
+ language = "plaintext",
24
+ height = "calc(100vh - 12rem)",
25
+ options,
26
+ }) => {
27
+ const monacoOptions = useMemo(() => {
28
+ const hideUnchanged = options?.onlyChanged
29
+ ? {
30
+ enabled: true,
31
+ revealLineCount: Math.max(0, options?.context ?? 3),
32
+ }
33
+ : undefined;
34
+
35
+ const opts = {
36
+ readOnly: true,
37
+ renderSideBySide: true,
38
+ renderOverviewRuler: true,
39
+ renderIndicators: true,
40
+ // Enable diff-editor level word wrap (VSCode has a separate setting for this)
41
+ diffWordWrap: "on",
42
+ wordWrap: options?.wordWrap ?? "on",
43
+ // Force both sides to honor wrap regardless of per-side defaults
44
+ wordWrapOverride1: "on",
45
+ wordWrapOverride2: "on",
46
+ wordWrapMinified: true,
47
+ wrappingStrategy: "advanced",
48
+ // Ensure even original (left) honors wrapping consistently
49
+ originalEditable: false,
50
+ ignoreTrimWhitespace: options?.ignoreWhitespace ?? true,
51
+ // @ts-ignore - monaco types may vary by version; it's safe to pass through
52
+ hideUnchangedRegions: hideUnchanged,
53
+ // @ts-ignore - prefer advanced algorithm if available
54
+ diffAlgorithm: "advanced",
55
+ // @ts-ignore - hide horizontal scrollbar when wrapping
56
+ scrollbar: {
57
+ vertical: 'auto',
58
+ horizontal: 'hidden',
59
+ horizontalScrollbarSize: 0,
60
+ },
61
+ // keep view lean
62
+ minimap: { enabled: false },
63
+ scrollBeyondLastLine: false,
64
+ automaticLayout: true,
65
+ } as any;
66
+ return opts;
67
+ }, [options]);
68
+
69
+ const editorRef = useRef<any>(null);
70
+
71
+ // Keep both panes in sync when options change
72
+ useEffect(() => {
73
+ const editor = editorRef.current;
74
+ if (!editor) return;
75
+ try {
76
+ const wrap = options?.wordWrap ?? "on";
77
+ const original = editor.getOriginalEditor?.();
78
+ const modified = editor.getModifiedEditor?.();
79
+ const shared = { wordWrap: wrap, wordWrapMinified: true, wrappingStrategy: 'advanced', scrollbar: { horizontal: 'hidden', horizontalScrollbarSize: 0 } } as any;
80
+ original?.updateOptions?.(shared);
81
+ modified?.updateOptions?.(shared);
82
+ } catch {}
83
+ }, [options?.wordWrap]);
84
+
85
+ // Ensure diff editor is fully disposed on unmount to avoid Monaco race conditions
86
+ useEffect(() => {
87
+ return () => {
88
+ try {
89
+ const editor: any = editorRef.current;
90
+ if (editor) {
91
+ try { editor.setModel?.(null); } catch {}
92
+ try { editor.getOriginalEditor?.()?.setModel?.(null); } catch {}
93
+ try { editor.getModifiedEditor?.()?.setModel?.(null); } catch {}
94
+ try { editor.dispose?.(); } catch {}
95
+ }
96
+ } catch {}
97
+ editorRef.current = null as any;
98
+ try { (window as any).__DIFF = undefined; } catch {}
99
+ };
100
+ }, []);
101
+
102
+ // Vertical resizable container: keep width 100%, allow drag to change height
103
+ const initialPxHeight = useMemo(() => {
104
+ // If a pixel value is provided, use it directly
105
+ if (typeof height === 'string') {
106
+ const pxMatch = height.match(/(\d+)px$/);
107
+ if (pxMatch) {
108
+ try { return parseInt(pxMatch[1], 10); } catch { /* ignore */ }
109
+ }
110
+
111
+ // Support calc(100vh - Xrem)
112
+ const calcRemMatch = height.match(/calc\(100vh\s*-\s*(\d+(?:\.\d+)?)rem\)/i);
113
+ if (calcRemMatch && typeof window !== 'undefined') {
114
+ const rem = parseFloat(calcRemMatch[1]);
115
+ const remPx = rem * 16; // assume 1rem = 16px baseline
116
+ return Math.max(240, Math.round(window.innerHeight - remPx));
117
+ }
118
+
119
+ // Support plain vh values (e.g., 80vh)
120
+ const vhMatch = height.match(/(\d+(?:\.\d+)?)vh/i);
121
+ if (vhMatch && typeof window !== 'undefined') {
122
+ const vh = parseFloat(vhMatch[1]);
123
+ return Math.max(240, Math.round(window.innerHeight * (vh / 100)));
124
+ }
125
+ }
126
+
127
+ // Fallback: viewport height minus 16rem (~256px) if available; otherwise 600px
128
+ if (typeof window !== 'undefined') {
129
+ return Math.max(240, window.innerHeight - 256);
130
+ }
131
+ return 600;
132
+ }, [height]);
133
+
134
+ const [containerHeight, setContainerHeight] = useState<number>(initialPxHeight);
135
+
136
+ return (
137
+ <div className="w-full border border-gray-200 rounded bg-white">
138
+ <div
139
+ className="w-full resize-y overflow-auto"
140
+ style={{ height: `${containerHeight}px`, minHeight: 240 }}
141
+ // Browser native resize-y changes element height; Monaco autoLayout observes size
142
+ onMouseUp={() => {
143
+ // Capture final height after drag (optional state sync)
144
+ try {
145
+ const node = (editorRef.current as any)?.getDomNode?.();
146
+ if (node && (node as HTMLElement).parentElement) {
147
+ const h = (node as HTMLElement).parentElement!.clientHeight;
148
+ if (h > 0) setContainerHeight(h);
149
+ }
150
+ } catch {}
151
+ }}
152
+ >
153
+ <DiffEditor
154
+ height="100%"
155
+ language={language === "python" ? "python" : "plaintext"}
156
+ original={leftContent ?? ""}
157
+ modified={rightContent ?? ""}
158
+ options={monacoOptions}
159
+ theme="light"
160
+ // Ensure both panes use the same wrapping and scrollbar behavior
161
+ onMount={(editor: any) => {
162
+ try {
163
+ editorRef.current = editor;
164
+
165
+ const applyWrap = (_when: string) => {
166
+ try {
167
+ const wrap = options?.wordWrap ?? "on";
168
+ const original = editor.getOriginalEditor?.();
169
+ const modified = editor.getModifiedEditor?.();
170
+ const shared = { wordWrap: wrap, wordWrapMinified: true, wrappingStrategy: 'advanced', wrappingIndent: 'same', scrollbar: { horizontal: 'hidden', horizontalScrollbarSize: 0 } } as any;
171
+ original?.updateOptions?.(shared);
172
+ modified?.updateOptions?.(shared);
173
+ // Force layout after changing wrap
174
+ try { original?.layout?.(); } catch {}
175
+ try { modified?.layout?.(); } catch {}
176
+ } catch (e) {
177
+ // swallow errors
178
+ }
179
+ };
180
+
181
+ // Apply at several timing points to avoid initialization overwrites
182
+ applyWrap('onMount immediate');
183
+ requestAnimationFrame(() => applyWrap('onMount rAF'));
184
+ setTimeout(() => applyWrap('onMount t=0'), 0);
185
+ setTimeout(() => applyWrap('onMount t=100'), 100);
186
+ setTimeout(() => applyWrap('onMount t=300'), 300);
187
+
188
+ // Re-apply on diff/layout/model changes
189
+ try { editor.onDidUpdateDiff?.(() => applyWrap('onDidUpdateDiff')); } catch {}
190
+ try { editor.getOriginalEditor?.()?.onDidLayoutChange?.(() => applyWrap('original onDidLayoutChange')); } catch {}
191
+ try { editor.getModifiedEditor?.()?.onDidLayoutChange?.(() => applyWrap('modified onDidLayoutChange')); } catch {}
192
+ try { editor.getOriginalEditor?.()?.onDidChangeModel?.(() => applyWrap('original onDidChangeModel')); } catch {}
193
+ try { editor.getModifiedEditor?.()?.onDidChangeModel?.(() => applyWrap('modified onDidChangeModel')); } catch {}
194
+ } catch (e) {
195
+ // swallow errors
196
+ }
197
+ }}
198
+ loading={<div className="p-4 text-gray-600">Loading diff viewer...</div>}
199
+ />
200
+ </div>
201
+ </div>
202
+ );
203
+ };
204
+
205
+ export default DiffComparisonView;
206
+
207
+