You've already forked objdiff-web
mirror of
https://github.com/encounter/objdiff-web.git
synced 2026-07-10 12:18:37 -07:00
Initial commit
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# Local
|
||||||
|
.DS_Store
|
||||||
|
*.local
|
||||||
|
*.log*
|
||||||
|
|
||||||
|
# Dist
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode-test/
|
||||||
|
*.vsix
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": [
|
||||||
|
"ms-vscode.extension-test-runner",
|
||||||
|
"jacobcassidy.css-nesting-syntax-highlighting"
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Run Extension",
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
|
||||||
|
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
|
||||||
|
// "preLaunchTask": "${defaultBuildTask}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+38
@@ -0,0 +1,38 @@
|
|||||||
|
// Place your settings in this file to overwrite default and user settings.
|
||||||
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.organizeImports.biome": "always"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||||
|
"typescript.tsc.autoDetect": "off",
|
||||||
|
|
||||||
|
"[css]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
},
|
||||||
|
"[scss]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
},
|
||||||
|
"[javascriptreact]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
},
|
||||||
|
"[typescriptreact]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
},
|
||||||
|
"[jsonc]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
},
|
||||||
|
"[yaml]": {
|
||||||
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"isBackground": true,
|
||||||
|
"label": "npm:watch",
|
||||||
|
"presentation": {
|
||||||
|
"group": "watch",
|
||||||
|
"reveal": "never"
|
||||||
|
},
|
||||||
|
"problemMatcher": "$tsc-watch"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
.vscode/**
|
||||||
|
.vscode-test/**
|
||||||
|
out/**
|
||||||
|
node_modules/**
|
||||||
|
src/**
|
||||||
|
webview/**
|
||||||
|
.gitignore
|
||||||
|
.yarnrc
|
||||||
|
rsbuild.config.ts
|
||||||
|
**/tsconfig.json
|
||||||
|
**/biome.json
|
||||||
|
**/*.map
|
||||||
|
**/*.ts
|
||||||
|
**/.vscode-test.*
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# objdiff-code
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> This extension is in early development and is **not yet ready for use**.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Open the project in Visual Studio Code.
|
||||||
|
|
||||||
|
- Install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
- Start dev server using `Ctrl+Shift+B` or by running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run watch
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run the extension in debug mode using `F5`.
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
|
||||||
|
"organizeImports": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"vcs": {
|
||||||
|
"enabled": true,
|
||||||
|
"clientKind": "git",
|
||||||
|
"useIgnoreFile": true
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"indentStyle": "space"
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"css": {
|
||||||
|
"parser": {
|
||||||
|
"cssModules": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true,
|
||||||
|
"a11y": {
|
||||||
|
"all": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1515
File diff suppressed because it is too large
Load Diff
+2007
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3,1C1.89,1 1,1.89 1,3V14C1,15.11 1.89,16 3,16H5V14H3V3H14V5H16V3C16,1.89 15.11,1 14,1H3M9,7C7.89,7 7,7.89 7,9V11H9V9H11V7H9M13,7V9H14V10H16V7H13M18,7V9H20V20H9V18H7V20C7,21.11 7.89,22 9,22H20C21.11,22 22,21.11 22,20V9C22,7.89 21.11,7 20,7H18M14,12V14H12V16H14C15.11,16 16,15.11 16,14V12H14M7,13V16H10V14H9V13H7Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
Generated
+3374
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"name": "objdiff-code",
|
||||||
|
"displayName": "objdiff-code",
|
||||||
|
"description": "objdiff",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"scripts": {
|
||||||
|
"build": "rsbuild build",
|
||||||
|
"watch": "rsbuild build --watch --mode development",
|
||||||
|
"check": "biome check --write",
|
||||||
|
"format": "biome format --write"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@protobuf-ts/runtime": "^2.9.4",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"memoize-one": "^6.0.0",
|
||||||
|
"picomatch": "^4.0.2",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"react-virtualized-auto-sizer": "^1.0.24",
|
||||||
|
"react-window": "^1.8.10",
|
||||||
|
"zustand": "^5.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "^1.9.3",
|
||||||
|
"@rsbuild/core": "^1.1.8",
|
||||||
|
"@rsbuild/plugin-react": "^1.0.7",
|
||||||
|
"@rsbuild/plugin-type-check": "^1.1.0",
|
||||||
|
"@types/picomatch": "^3.0.1",
|
||||||
|
"@types/react": "^18.3.1",
|
||||||
|
"@types/react-dom": "^18.3.1",
|
||||||
|
"@types/react-window": "^1.8.8",
|
||||||
|
"@types/vscode": "^1.96.0",
|
||||||
|
"@types/vscode-webview": "^1.57.5",
|
||||||
|
"@vscode/test-cli": "^0.0.10",
|
||||||
|
"@vscode/test-electron": "^2.4.1",
|
||||||
|
"typescript": "^5.7.2"
|
||||||
|
},
|
||||||
|
"main": "./dist/extension.js",
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.96.0"
|
||||||
|
},
|
||||||
|
"browserslist": ["chrome 128"],
|
||||||
|
"categories": ["Other"],
|
||||||
|
"activationEvents": ["*"],
|
||||||
|
"contributes": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"command": "objdiff.build",
|
||||||
|
"title": "objdiff: build"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration": {
|
||||||
|
"title": "objdiff",
|
||||||
|
"properties": {
|
||||||
|
"objdiff.binaryPath": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path to the objdiff-cli binary",
|
||||||
|
"ignoreSync": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"viewsContainers": {
|
||||||
|
"panel": [
|
||||||
|
{
|
||||||
|
"id": "objdiff",
|
||||||
|
"title": "objdiff",
|
||||||
|
"icon": "media/icon.svg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"views": {
|
||||||
|
"objdiff": [
|
||||||
|
{
|
||||||
|
"id": "objdiff",
|
||||||
|
"name": "objdiff",
|
||||||
|
"type": "webview"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"viewsWelcome": [
|
||||||
|
{
|
||||||
|
"view": "objdiff",
|
||||||
|
"contents": "Loading..."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"taskDefinitions": [
|
||||||
|
{
|
||||||
|
"type": "objdiff"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { defineConfig } from '@rsbuild/core';
|
||||||
|
import { pluginReact } from '@rsbuild/plugin-react';
|
||||||
|
import { pluginTypeCheck } from '@rsbuild/plugin-type-check';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
// Disable HMR and live reload. Neither the extension nor the
|
||||||
|
// webview can communicate with the rsbuild dev server.
|
||||||
|
dev: {
|
||||||
|
hmr: false,
|
||||||
|
liveReload: false,
|
||||||
|
},
|
||||||
|
environments: {
|
||||||
|
extension: {
|
||||||
|
source: {
|
||||||
|
entry: {
|
||||||
|
extension: './src/extension.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
target: 'node',
|
||||||
|
distPath: {
|
||||||
|
root: 'dist',
|
||||||
|
},
|
||||||
|
externals: ['vscode'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
webview: {
|
||||||
|
source: {
|
||||||
|
entry: {
|
||||||
|
index: './webview/index.tsx',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
target: 'web',
|
||||||
|
distPath: {
|
||||||
|
root: 'dist/webview',
|
||||||
|
},
|
||||||
|
// VS Code webviews don't have easy access to resources,
|
||||||
|
// (especially if the extension is running on web) so we
|
||||||
|
// simply inline everything into the HTML.
|
||||||
|
inlineScripts: true,
|
||||||
|
inlineStyles: true,
|
||||||
|
legalComments: 'none',
|
||||||
|
},
|
||||||
|
// <script defer> doesn't work with inline scripts,
|
||||||
|
// so we need to move the scripts to the body.
|
||||||
|
html: {
|
||||||
|
inject: 'body',
|
||||||
|
scriptLoading: 'blocking',
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
pluginReact({
|
||||||
|
fastRefresh: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Ensure that we never split chunks. Both the extension and
|
||||||
|
// the webview must be self-contained files.
|
||||||
|
performance: {
|
||||||
|
chunkSplit: {
|
||||||
|
strategy: 'all-in-one',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Enable async TypeScript type checking.
|
||||||
|
plugins: [pluginTypeCheck()],
|
||||||
|
// We can't use async chunks for aforementioned reasons.
|
||||||
|
// Disabling them ensures that all code is bundled together
|
||||||
|
// even if dynamic imports are used.
|
||||||
|
tools: {
|
||||||
|
rspack: {
|
||||||
|
output: {
|
||||||
|
asyncChunks: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
+182
@@ -0,0 +1,182 @@
|
|||||||
|
// import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
export const DEFAULT_WATCH_PATTERNS = [
|
||||||
|
'*.c',
|
||||||
|
'*.cp',
|
||||||
|
'*.cpp',
|
||||||
|
'*.cxx',
|
||||||
|
'*.h',
|
||||||
|
'*.hp',
|
||||||
|
'*.hpp',
|
||||||
|
'*.hxx',
|
||||||
|
'*.s',
|
||||||
|
'*.S',
|
||||||
|
'*.asm',
|
||||||
|
'*.inc',
|
||||||
|
'*.py',
|
||||||
|
'*.yml',
|
||||||
|
'*.txt',
|
||||||
|
'*.json',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration file for objdiff
|
||||||
|
*/
|
||||||
|
export interface ObjdiffConfiguration {
|
||||||
|
/**
|
||||||
|
* Minimum version of objdiff required to load this configuration file.
|
||||||
|
*/
|
||||||
|
min_version?: string;
|
||||||
|
/**
|
||||||
|
* By default, objdiff will use make to build the project.
|
||||||
|
* If the project uses a different build system (e.g. ninja), specify it here.
|
||||||
|
* The build command will be `[custom_make] [custom_args] path/to/object.o`.
|
||||||
|
*/
|
||||||
|
custom_make?: string;
|
||||||
|
/**
|
||||||
|
* Additional arguments to pass to the build command prior to the object path.
|
||||||
|
*/
|
||||||
|
custom_args?: string[];
|
||||||
|
/**
|
||||||
|
* Relative from the root of the project, this where the "target" or "expected" objects are located.
|
||||||
|
* These are the intended result of the match.
|
||||||
|
*/
|
||||||
|
target_dir?: string;
|
||||||
|
/**
|
||||||
|
* Relative from the root of the project, this is where the "base" or "actual" objects are located.
|
||||||
|
* These are objects built from the current source code.
|
||||||
|
*/
|
||||||
|
base_dir?: string;
|
||||||
|
/**
|
||||||
|
* If true, objdiff will tell the build system to build the target objects before diffing (e.g. `make path/to/target.o`).
|
||||||
|
* This is useful if the target objects are not built by default or can change based on project configuration or edits to assembly files.
|
||||||
|
* Requires the build system to be configured properly.
|
||||||
|
*/
|
||||||
|
build_target?: boolean;
|
||||||
|
/**
|
||||||
|
* If true, objdiff will tell the build system to build the base objects before diffing (e.g. `make path/to/base.o`).
|
||||||
|
* It's unlikely you'll want to disable this, unless you're using an external tool to rebuild the base object on source file changes.
|
||||||
|
*/
|
||||||
|
build_base?: boolean;
|
||||||
|
/**
|
||||||
|
* List of glob patterns to watch for changes in the project.
|
||||||
|
* If any of these files change, objdiff will automatically rebuild the objects and re-compare them.
|
||||||
|
* Supported syntax: https://docs.rs/globset/latest/globset/#syntax
|
||||||
|
*/
|
||||||
|
watch_patterns?: string[];
|
||||||
|
/**
|
||||||
|
* Use units instead.
|
||||||
|
*/
|
||||||
|
objects?: Unit[];
|
||||||
|
/**
|
||||||
|
* If specified, objdiff will display a list of objects in the sidebar for easy navigation.
|
||||||
|
*/
|
||||||
|
units?: Unit[];
|
||||||
|
/**
|
||||||
|
* Progress categories used for objdiff-cli report.
|
||||||
|
*/
|
||||||
|
progress_categories?: ProgressCategory[];
|
||||||
|
}
|
||||||
|
export interface Unit {
|
||||||
|
/**
|
||||||
|
* The name of the object in the UI. If not specified, the object's path will be used.
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
/**
|
||||||
|
* Relative path to the object from the target_dir and base_dir.
|
||||||
|
* Requires target_dir and base_dir to be specified.
|
||||||
|
*/
|
||||||
|
path?: string;
|
||||||
|
/**
|
||||||
|
* Path to the target object from the project root.
|
||||||
|
* Required if path is not specified.
|
||||||
|
*/
|
||||||
|
target_path?: string;
|
||||||
|
/**
|
||||||
|
* Path to the base object from the project root.
|
||||||
|
* Required if path is not specified.
|
||||||
|
*/
|
||||||
|
base_path?: string;
|
||||||
|
/**
|
||||||
|
* Displays function symbols in reversed order.
|
||||||
|
* Used to support MWCC's -inline deferred option, which reverses the order of functions in the object file.
|
||||||
|
*/
|
||||||
|
reverse_fn_order?: boolean;
|
||||||
|
/**
|
||||||
|
* Marks the object as "complete" (or "linked") in the object list.
|
||||||
|
* This is useful for marking objects that are fully decompiled. A value of `false` will mark the object as "incomplete".
|
||||||
|
*/
|
||||||
|
complete?: boolean;
|
||||||
|
/**
|
||||||
|
* If present, objdiff will display a button to create a decomp.me scratch.
|
||||||
|
*/
|
||||||
|
scratch?: Scratch;
|
||||||
|
/**
|
||||||
|
* Metadata for the object.
|
||||||
|
*/
|
||||||
|
metadata?: Metadata;
|
||||||
|
/**
|
||||||
|
* Manual symbol mappings from target to base.
|
||||||
|
*/
|
||||||
|
symbol_mappings?: {
|
||||||
|
[k: string]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export interface Scratch {
|
||||||
|
/**
|
||||||
|
* The decomp.me platform ID to use for the scratch.
|
||||||
|
*/
|
||||||
|
platform?: string;
|
||||||
|
/**
|
||||||
|
* The decomp.me compiler ID to use for the scratch.
|
||||||
|
*/
|
||||||
|
compiler?: string;
|
||||||
|
/**
|
||||||
|
* C flags to use for the scratch. Exclude any include paths.
|
||||||
|
*/
|
||||||
|
c_flags?: string;
|
||||||
|
/**
|
||||||
|
* Path to the context file to use for the scratch.
|
||||||
|
*/
|
||||||
|
ctx_path?: string;
|
||||||
|
/**
|
||||||
|
* If true, objdiff will run the build command with the context file as an argument to generate it.
|
||||||
|
*/
|
||||||
|
build_ctx?: boolean;
|
||||||
|
}
|
||||||
|
export interface Metadata {
|
||||||
|
/**
|
||||||
|
* Marks the object as "complete" (or "linked") in the object list.
|
||||||
|
* This is useful for marking objects that are fully decompiled. A value of `false` will mark the object as "incomplete".
|
||||||
|
*/
|
||||||
|
complete?: boolean;
|
||||||
|
/**
|
||||||
|
* Displays function symbols in reversed order.
|
||||||
|
* Used to support MWCC's -inline deferred option, which reverses the order of functions in the object file.
|
||||||
|
*/
|
||||||
|
reverse_fn_order?: boolean;
|
||||||
|
/**
|
||||||
|
* Path to the source file that generated the object.
|
||||||
|
*/
|
||||||
|
source_path?: string;
|
||||||
|
/**
|
||||||
|
* Progress categories used for objdiff-cli report.
|
||||||
|
*/
|
||||||
|
progress_categories?: string[];
|
||||||
|
/**
|
||||||
|
* Hides the object from the object list by default, but still includes it in reports.
|
||||||
|
*/
|
||||||
|
auto_generated?: boolean;
|
||||||
|
}
|
||||||
|
export interface ProgressCategory {
|
||||||
|
/**
|
||||||
|
* Unique identifier for the category.
|
||||||
|
*/
|
||||||
|
id?: string;
|
||||||
|
/**
|
||||||
|
* Human-readable name of the category.
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadConfig() {}
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="@rsbuild/core/types" />
|
||||||
@@ -0,0 +1,464 @@
|
|||||||
|
import * as picomatch from 'picomatch';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import { DEFAULT_WATCH_PATTERNS, type ObjdiffConfiguration } from './config';
|
||||||
|
|
||||||
|
const CONFIG_FILENAME = 'objdiff.json';
|
||||||
|
|
||||||
|
export class ObjdiffWorkspace extends vscode.Disposable {
|
||||||
|
public config?: ObjdiffConfiguration;
|
||||||
|
public configWatcher: vscode.FileSystemWatcher;
|
||||||
|
public workspaceWatcher?: vscode.FileSystemWatcher;
|
||||||
|
|
||||||
|
private subscriptions: vscode.Disposable[] = [];
|
||||||
|
private wwSubscriptions: vscode.Disposable[] = [];
|
||||||
|
private currentDiff?: vscode.Uri;
|
||||||
|
// private currentTask?: () => void;
|
||||||
|
private pathMatcher?: picomatch.Matcher;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly chan: vscode.LogOutputChannel,
|
||||||
|
public readonly workspaceFolder: vscode.WorkspaceFolder,
|
||||||
|
private readonly storageUri: vscode.Uri,
|
||||||
|
) {
|
||||||
|
super(() => {
|
||||||
|
this.disposeImpl();
|
||||||
|
});
|
||||||
|
this.configWatcher = vscode.workspace.createFileSystemWatcher(
|
||||||
|
new vscode.RelativePattern(workspaceFolder, CONFIG_FILENAME),
|
||||||
|
);
|
||||||
|
this.configWatcher.onDidCreate(this.loadConfig, this, this.subscriptions);
|
||||||
|
this.configWatcher.onDidChange(this.loadConfig, this, this.subscriptions);
|
||||||
|
this.configWatcher.onDidDelete(this.loadConfig, this, this.subscriptions);
|
||||||
|
this.loadConfig();
|
||||||
|
chan.info(`Initialized workspace: ${this.workspaceFolder.uri.toString()}`);
|
||||||
|
// this.subscriptions.push(
|
||||||
|
// vscode.workspace.onDidOpenTextDocument((e) => {
|
||||||
|
// if (
|
||||||
|
// e.uri.scheme === 'file' &&
|
||||||
|
// e.uri.fsPath.startsWith(this.rootUri.fsPath)
|
||||||
|
// ) {
|
||||||
|
// const relPath = e.uri.fsPath.slice(this.rootUri.fsPath.length + 1);
|
||||||
|
// this.chan.info('Opened document in workspace:', relPath);
|
||||||
|
// }
|
||||||
|
// }, this),
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: pass through message args
|
||||||
|
showError(message: string, ...args: any[]) {
|
||||||
|
this.chan.error(message, ...args);
|
||||||
|
vscode.window
|
||||||
|
.showErrorMessage(`objdiff: ${message}`, {
|
||||||
|
title: 'Show log',
|
||||||
|
})
|
||||||
|
.then((item) => {
|
||||||
|
if (item) {
|
||||||
|
this.chan.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadConfig() {
|
||||||
|
const configUri = vscode.Uri.joinPath(
|
||||||
|
this.workspaceFolder.uri,
|
||||||
|
CONFIG_FILENAME,
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const stat = await vscode.workspace.fs.stat(configUri);
|
||||||
|
if (stat.type !== vscode.FileType.File) {
|
||||||
|
this.showError('Config path is not a file', configUri.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (reason) {
|
||||||
|
if (reason instanceof vscode.FileSystemError) {
|
||||||
|
if (reason.code === 'FileNotFound') {
|
||||||
|
this.chan.warn('Config file not found', configUri.toString());
|
||||||
|
this.config = undefined;
|
||||||
|
this.onConfigChange();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.showError(
|
||||||
|
'Failed to stat config file',
|
||||||
|
configUri.toString(),
|
||||||
|
reason,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = await vscode.workspace.fs.readFile(configUri);
|
||||||
|
this.config = JSON.parse(new TextDecoder().decode(data));
|
||||||
|
} catch (reason) {
|
||||||
|
this.showError(
|
||||||
|
'Failed to load config file',
|
||||||
|
configUri.toString(),
|
||||||
|
reason,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.onConfigChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
onConfigChange() {
|
||||||
|
this.chan.info('Loaded new config');
|
||||||
|
const watchPatterns = this.config?.watch_patterns || DEFAULT_WATCH_PATTERNS;
|
||||||
|
if (watchPatterns.length) {
|
||||||
|
this.pathMatcher = picomatch(watchPatterns, {
|
||||||
|
basename: true,
|
||||||
|
strictSlashes: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.pathMatcher = undefined;
|
||||||
|
}
|
||||||
|
this.chan.info('Watch patterns:', watchPatterns);
|
||||||
|
if (this.workspaceWatcher) {
|
||||||
|
for (const sub of this.wwSubscriptions) {
|
||||||
|
sub.dispose();
|
||||||
|
}
|
||||||
|
this.wwSubscriptions = [];
|
||||||
|
this.workspaceWatcher.dispose();
|
||||||
|
this.workspaceWatcher = undefined;
|
||||||
|
}
|
||||||
|
if (this.pathMatcher) {
|
||||||
|
this.workspaceWatcher = vscode.workspace.createFileSystemWatcher(
|
||||||
|
new vscode.RelativePattern(this.workspaceFolder.uri, '*/**'),
|
||||||
|
);
|
||||||
|
this.workspaceWatcher.onDidChange(
|
||||||
|
this.onWorkspaceFileChange,
|
||||||
|
this,
|
||||||
|
this.wwSubscriptions,
|
||||||
|
);
|
||||||
|
this.workspaceWatcher.onDidCreate(
|
||||||
|
this.onWorkspaceFileChange,
|
||||||
|
this,
|
||||||
|
this.wwSubscriptions,
|
||||||
|
);
|
||||||
|
this.workspaceWatcher.onDidDelete(
|
||||||
|
this.onWorkspaceFileChange,
|
||||||
|
this,
|
||||||
|
this.wwSubscriptions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.tryDiff();
|
||||||
|
}
|
||||||
|
|
||||||
|
onWorkspaceFileChange(uri: vscode.Uri) {
|
||||||
|
if (!uri.fsPath.startsWith(this.workspaceFolder.uri.fsPath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const relPath = uri.fsPath.slice(
|
||||||
|
this.workspaceFolder.uri.fsPath.length + 1,
|
||||||
|
);
|
||||||
|
if (!this.pathMatcher || !this.pathMatcher(relPath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.chan.info('Workspace file changed', uri.toString());
|
||||||
|
this.tryDiff();
|
||||||
|
}
|
||||||
|
|
||||||
|
tryDiff() {
|
||||||
|
if (!this.config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.currentDiff) {
|
||||||
|
const activeEditor = vscode.window.activeTextEditor;
|
||||||
|
if (!activeEditor) {
|
||||||
|
this.chan.warn('No active editor');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (activeEditor.document.uri.scheme !== 'file') {
|
||||||
|
this.chan.warn('Active editor not a file');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.currentDiff = activeEditor.document.uri;
|
||||||
|
}
|
||||||
|
const fsPath = this.currentDiff.fsPath;
|
||||||
|
if (!fsPath.startsWith(this.workspaceFolder.uri.fsPath)) {
|
||||||
|
this.chan.warn('Active editor not in workspace');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const relPath = fsPath.slice(this.workspaceFolder.uri.fsPath.length + 1);
|
||||||
|
const obj = (this.config.units || this.config.objects)?.find(
|
||||||
|
(obj) => obj.metadata?.source_path === relPath,
|
||||||
|
);
|
||||||
|
if (!obj) {
|
||||||
|
this.chan.warn('No object found for', relPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const targetPath =
|
||||||
|
obj.target_path &&
|
||||||
|
vscode.Uri.joinPath(this.workspaceFolder.uri, obj.target_path);
|
||||||
|
const basePath =
|
||||||
|
obj.base_path &&
|
||||||
|
vscode.Uri.joinPath(this.workspaceFolder.uri, obj.base_path);
|
||||||
|
this.chan.info('Diffing', targetPath?.toString(), basePath?.toString());
|
||||||
|
if (!targetPath || !basePath) {
|
||||||
|
this.chan.warn('Missing target or base path');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const buildCmd = this.config.custom_make || 'make';
|
||||||
|
const buildArgs = this.config.custom_args || [];
|
||||||
|
const outputUri = vscode.Uri.joinPath(this.storageUri, 'diff.binpb');
|
||||||
|
const args = [];
|
||||||
|
if (obj.target_path && this.config.build_target) {
|
||||||
|
if (args.length) {
|
||||||
|
args.push('&&');
|
||||||
|
}
|
||||||
|
args.push(buildCmd, ...buildArgs, obj.target_path);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
obj.base_path &&
|
||||||
|
(this.config.build_base || this.config.build_base === undefined)
|
||||||
|
) {
|
||||||
|
if (args.length) {
|
||||||
|
args.push('&&');
|
||||||
|
}
|
||||||
|
args.push(buildCmd, ...buildArgs, obj.base_path);
|
||||||
|
}
|
||||||
|
if (args.length) {
|
||||||
|
args.push('&&');
|
||||||
|
}
|
||||||
|
const binaryPath = vscode.workspace
|
||||||
|
.getConfiguration('objdiff')
|
||||||
|
.get('binaryPath') as string;
|
||||||
|
if (!binaryPath) {
|
||||||
|
vscode.window
|
||||||
|
.showWarningMessage('objdiff.binaryPath not set', {
|
||||||
|
title: 'Open settings',
|
||||||
|
})
|
||||||
|
.then((item) => {
|
||||||
|
if (item) {
|
||||||
|
vscode.commands.executeCommand(
|
||||||
|
'workbench.action.openSettings',
|
||||||
|
'objdiff.binaryPath',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
args.push(
|
||||||
|
binaryPath,
|
||||||
|
'diff',
|
||||||
|
'-1',
|
||||||
|
targetPath.fsPath,
|
||||||
|
'-2',
|
||||||
|
basePath.fsPath,
|
||||||
|
'--format',
|
||||||
|
'proto',
|
||||||
|
'-o',
|
||||||
|
outputUri.fsPath,
|
||||||
|
);
|
||||||
|
const startTime = performance.now();
|
||||||
|
const task = new vscode.Task(
|
||||||
|
{
|
||||||
|
type: 'objdiff',
|
||||||
|
startTime,
|
||||||
|
},
|
||||||
|
this.workspaceFolder,
|
||||||
|
'objdiff',
|
||||||
|
'objdiff',
|
||||||
|
new vscode.ShellExecution(args[0], args.slice(1)),
|
||||||
|
);
|
||||||
|
task.presentationOptions.reveal = vscode.TaskRevealKind.Silent;
|
||||||
|
vscode.tasks.executeTask(task).then(
|
||||||
|
({ task, terminate: _ }) => {
|
||||||
|
const curTime = performance.now();
|
||||||
|
this.chan.info(
|
||||||
|
'Diff task started in',
|
||||||
|
curTime - task.definition.startTime,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(reason) => {
|
||||||
|
this.showError('Failed to start diff task', reason);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private disposeImpl() {
|
||||||
|
this.chan.info('Disposing workspace');
|
||||||
|
this.configWatcher.dispose();
|
||||||
|
for (const sub of this.wwSubscriptions) {
|
||||||
|
sub.dispose();
|
||||||
|
}
|
||||||
|
this.wwSubscriptions = [];
|
||||||
|
this.workspaceWatcher?.dispose();
|
||||||
|
this.workspaceWatcher = undefined;
|
||||||
|
for (const sub of this.subscriptions) {
|
||||||
|
sub.dispose();
|
||||||
|
}
|
||||||
|
this.subscriptions = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
|
const chan = vscode.window.createOutputChannel('objdiff', { log: true });
|
||||||
|
const storageUri = context.storageUri;
|
||||||
|
if (!storageUri || storageUri.scheme !== 'file') {
|
||||||
|
vscode.window.showErrorMessage('objdiff requires a file storage URI');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vscode.workspace.fs.createDirectory(storageUri).then(
|
||||||
|
() => {
|
||||||
|
chan.info('Storage directory created', storageUri.toString());
|
||||||
|
},
|
||||||
|
(reason) => {
|
||||||
|
chan.error(
|
||||||
|
'Failed to create storage directory',
|
||||||
|
storageUri.toString(),
|
||||||
|
reason,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// const storageDir = storageUri.fsPath;
|
||||||
|
// chan.info('Storage directory: ' + storageDir);
|
||||||
|
|
||||||
|
let workspace: ObjdiffWorkspace | undefined;
|
||||||
|
if (vscode.workspace.workspaceFolders?.[0]) {
|
||||||
|
workspace = new ObjdiffWorkspace(
|
||||||
|
chan,
|
||||||
|
vscode.workspace.workspaceFolders[0],
|
||||||
|
storageUri,
|
||||||
|
);
|
||||||
|
context.subscriptions.push(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.commands.registerCommand('objdiff.build', () => {
|
||||||
|
if (workspace) {
|
||||||
|
workspace.tryDiff();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const webviews: vscode.Webview[] = [];
|
||||||
|
|
||||||
|
const backgroundColors = [
|
||||||
|
'rgba(255, 0, 255, 0.3)',
|
||||||
|
'rgba(0, 255, 255, 0.3)',
|
||||||
|
'rgba(0, 212, 0, 0.3)',
|
||||||
|
'rgba(255, 0, 0, 0.3)',
|
||||||
|
'rgba(103, 106, 255, 0.3)',
|
||||||
|
'rgba(255, 182, 193, 0.3)',
|
||||||
|
'rgba(224, 255, 255, 0.3)',
|
||||||
|
'rgba(144, 238, 144, 0.3)',
|
||||||
|
'rgba(128, 128, 128, 0.3)',
|
||||||
|
];
|
||||||
|
const decorationTypes = backgroundColors.map((color) => {
|
||||||
|
return vscode.window.createTextEditorDecorationType({
|
||||||
|
isWholeLine: true,
|
||||||
|
backgroundColor: color,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.tasks.onDidEndTaskProcess(async (e) => {
|
||||||
|
if (e.execution.task.definition.type !== 'objdiff') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const endTime = performance.now();
|
||||||
|
chan.info(
|
||||||
|
'Task ended',
|
||||||
|
e.exitCode,
|
||||||
|
endTime - e.execution.task.definition.startTime,
|
||||||
|
);
|
||||||
|
const proc = e.execution.task.execution as vscode.ProcessExecution;
|
||||||
|
const outputFile = proc.args[proc.args.indexOf('-o') + 1];
|
||||||
|
const outputUri = vscode.Uri.file(outputFile);
|
||||||
|
if (e.exitCode === 0) {
|
||||||
|
try {
|
||||||
|
const data = await vscode.workspace.fs.readFile(outputUri);
|
||||||
|
chan.info(
|
||||||
|
'Read output file',
|
||||||
|
outputFile,
|
||||||
|
'with size',
|
||||||
|
data.byteLength,
|
||||||
|
);
|
||||||
|
// const diff = diff_pb.DiffResult.fromBinary(data);
|
||||||
|
// treeDataProvider.update(diff);
|
||||||
|
// vscode.window.showInformationMessage('Diff complete');
|
||||||
|
// console.log('webviews', webviews);
|
||||||
|
for (const webview of webviews) {
|
||||||
|
webview.postMessage({
|
||||||
|
type: 'diff',
|
||||||
|
data: data.buffer,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (reason) {
|
||||||
|
chan.error('Failed to read output file', reason);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
workspace?.showError(`Build failed with code ${e.exitCode}`);
|
||||||
|
}
|
||||||
|
vscode.workspace.fs.delete(outputUri).then(
|
||||||
|
() => {},
|
||||||
|
(reason) => {
|
||||||
|
chan.error('Failed to delete output file', reason);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const textDecoder = new TextDecoder();
|
||||||
|
const webviewRoot = vscode.Uri.joinPath(
|
||||||
|
context.extensionUri,
|
||||||
|
'dist',
|
||||||
|
'webview',
|
||||||
|
);
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.window.registerWebviewViewProvider('objdiff', {
|
||||||
|
async resolveWebviewView(view, _resolve, _token) {
|
||||||
|
let html = textDecoder.decode(
|
||||||
|
await vscode.workspace.fs.readFile(
|
||||||
|
vscode.Uri.joinPath(webviewRoot, 'index.html'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// For development, allow static assets (production will be inlined)
|
||||||
|
html = html.replaceAll(/"\/static\/(.*?)"/g, (_, p) => {
|
||||||
|
const assetUri = vscode.Uri.joinPath(webviewRoot, 'static', p);
|
||||||
|
return `"${view.webview.asWebviewUri(assetUri)}"`;
|
||||||
|
});
|
||||||
|
// chan.info(html);
|
||||||
|
view.webview.options = {
|
||||||
|
localResourceRoots: [context.extensionUri],
|
||||||
|
enableScripts: true,
|
||||||
|
};
|
||||||
|
view.webview.html = html;
|
||||||
|
context.subscriptions.push(
|
||||||
|
view.webview.onDidReceiveMessage((message) => {
|
||||||
|
if (message.type === 'ready') {
|
||||||
|
chan.info('Webview ready');
|
||||||
|
} else if (message.type === 'lineRanges') {
|
||||||
|
for (const editor of vscode.window.visibleTextEditors) {
|
||||||
|
if (editor.document.uri.scheme !== 'file') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chan.info(
|
||||||
|
'Adding decorations to editor',
|
||||||
|
editor.document.uri.toString(),
|
||||||
|
);
|
||||||
|
let idx = 0;
|
||||||
|
for (const range of message.data) {
|
||||||
|
editor.setDecorations(decorationTypes[idx], [
|
||||||
|
new vscode.Range(range.start, 0, range.end, 0),
|
||||||
|
]);
|
||||||
|
idx = (idx + 1) % decorationTypes.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
context.subscriptions.push(
|
||||||
|
view.onDidDispose(() => {
|
||||||
|
const idx = webviews.indexOf(view.webview);
|
||||||
|
if (idx >= 0) {
|
||||||
|
webviews.splice(idx, 1);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
webviews.push(view.webview);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deactivate() {}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": ["DOM", "ES2023"],
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"target": "ES2022",
|
||||||
|
"noEmit": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
|
||||||
|
/* modules */
|
||||||
|
"module": "ESNext",
|
||||||
|
"isolatedModules": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
|
||||||
|
/* type checking */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true
|
||||||
|
},
|
||||||
|
"include": ["src", "webview", "gen"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
:root {
|
||||||
|
--font-size: var(--vscode-editor-font-size, 13px);
|
||||||
|
--list-row-height: calc(var(--font-size) * 1.33);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
color: var(--vscode-editor-foreground, #fff);
|
||||||
|
font-family: var(
|
||||||
|
--vscode-font-family,
|
||||||
|
system-ui,
|
||||||
|
-apple-system,
|
||||||
|
BlinkMacSystemFont,
|
||||||
|
"Segoe UI",
|
||||||
|
Roboto,
|
||||||
|
"Helvetica Neue",
|
||||||
|
Arial,
|
||||||
|
sans-serif
|
||||||
|
);
|
||||||
|
background-color: var(--vscode-editor-background, #1e1e1e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
line-height: 1.1;
|
||||||
|
text-align: center;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content h1 {
|
||||||
|
font-size: 3.6rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content p {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 400;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import './App.css';
|
||||||
|
|
||||||
|
import { SectionKind } from '../gen/diff_pb';
|
||||||
|
import type {
|
||||||
|
Symbol as DiffSymbol,
|
||||||
|
FunctionDiff,
|
||||||
|
ObjectDiff,
|
||||||
|
} from '../gen/diff_pb';
|
||||||
|
import FunctionView from './FunctionView';
|
||||||
|
import SymbolsView from './SymbolsView';
|
||||||
|
import { useAppStore, useDiffStore } from './state';
|
||||||
|
import type { SymbolRefByName } from './state';
|
||||||
|
|
||||||
|
const findSymbol = (
|
||||||
|
obj: ObjectDiff | undefined,
|
||||||
|
symbolRef: SymbolRefByName | null,
|
||||||
|
): FunctionDiff | null => {
|
||||||
|
if (!obj || !symbolRef) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const section of obj.sections) {
|
||||||
|
if (section.name === symbolRef.section_name) {
|
||||||
|
if (section.kind === SectionKind.SECTION_TEXT) {
|
||||||
|
for (const fn of section.functions) {
|
||||||
|
const symbol = fn.symbol as DiffSymbol;
|
||||||
|
if (symbol.name === symbolRef.symbol_name) {
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
const { diff } = useDiffStore();
|
||||||
|
const selectedSymbolRef = useAppStore((state) => state.selectedSymbol);
|
||||||
|
|
||||||
|
if (diff) {
|
||||||
|
const object = diff.left || diff.right || { sections: [] };
|
||||||
|
const leftSymbol = findSymbol(diff.left, selectedSymbolRef);
|
||||||
|
const rightSymbol = findSymbol(diff.right, selectedSymbolRef);
|
||||||
|
if (leftSymbol || rightSymbol) {
|
||||||
|
return <FunctionView left={leftSymbol} right={rightSymbol} />;
|
||||||
|
}
|
||||||
|
return <SymbolsView obj={object} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="content">
|
||||||
|
<h1>objdiff</h1>
|
||||||
|
<p>Coming soon to a VS Code near you.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user