From 4d3800450ee21eea42e169c7c5e36aada3584d67 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 17 Dec 2024 21:49:23 -0700 Subject: [PATCH] Auto-build, full symbols view and diff view & more --- gen/report_pb.ts | 2007 ------------------------------- package.json | 44 +- rsbuild.config.ts | 1 + {gen => shared/gen}/diff_pb.ts | 136 ++- shared/messages.ts | 36 + src/extension.ts | 234 +++- tsconfig.json | 2 +- webview/App.css | 77 +- webview/App.tsx | 40 +- webview/FunctionView.module.css | 135 ++- webview/FunctionView.tsx | 91 +- webview/Header.module.css | 19 + webview/SymbolsView.module.css | 44 +- webview/SymbolsView.tsx | 155 ++- webview/diff.ts | 2 +- webview/state.ts | 144 ++- 16 files changed, 885 insertions(+), 2282 deletions(-) delete mode 100644 gen/report_pb.ts rename {gen => shared/gen}/diff_pb.ts (92%) create mode 100644 shared/messages.ts create mode 100644 webview/Header.module.css diff --git a/gen/report_pb.ts b/gen/report_pb.ts deleted file mode 100644 index 5416c0e..0000000 --- a/gen/report_pb.ts +++ /dev/null @@ -1,2007 +0,0 @@ -/* eslint-disable */ -// @generated by protobuf-ts 2.9.4 with parameter add_pb_suffix,eslint_disable,ts_nocheck,use_proto_field_name -// @generated from protobuf file "report.proto" (package "objdiff.report", syntax proto3) -// tslint:disable -// @ts-nocheck -import type { BinaryWriteOptions } from '@protobuf-ts/runtime'; -import type { IBinaryWriter } from '@protobuf-ts/runtime'; -import { WireType } from '@protobuf-ts/runtime'; -import type { BinaryReadOptions } from '@protobuf-ts/runtime'; -import type { IBinaryReader } from '@protobuf-ts/runtime'; -import { UnknownFieldHandler } from '@protobuf-ts/runtime'; -import type { PartialMessage } from '@protobuf-ts/runtime'; -import { reflectionMergePartial } from '@protobuf-ts/runtime'; -import { MessageType } from '@protobuf-ts/runtime'; -/** - * Progress info for a report or unit - * - * @generated from protobuf message objdiff.report.Measures - */ -export interface Measures { - /** - * Overall match percent, including partially matched functions and data - * - * @generated from protobuf field: float fuzzy_match_percent = 1; - */ - fuzzy_match_percent: number; - /** - * Total size of code in bytes - * - * @generated from protobuf field: uint64 total_code = 2; - */ - total_code: bigint; - /** - * Fully matched code size in bytes - * - * @generated from protobuf field: uint64 matched_code = 3; - */ - matched_code: bigint; - /** - * Fully matched code percent - * - * @generated from protobuf field: float matched_code_percent = 4; - */ - matched_code_percent: number; - /** - * Total size of data in bytes - * - * @generated from protobuf field: uint64 total_data = 5; - */ - total_data: bigint; - /** - * Fully matched data size in bytes - * - * @generated from protobuf field: uint64 matched_data = 6; - */ - matched_data: bigint; - /** - * Fully matched data percent - * - * @generated from protobuf field: float matched_data_percent = 7; - */ - matched_data_percent: number; - /** - * Total number of functions - * - * @generated from protobuf field: uint32 total_functions = 8; - */ - total_functions: number; - /** - * Fully matched functions - * - * @generated from protobuf field: uint32 matched_functions = 9; - */ - matched_functions: number; - /** - * Fully matched functions percent - * - * @generated from protobuf field: float matched_functions_percent = 10; - */ - matched_functions_percent: number; - /** - * Completed (or "linked") code size in bytes - * - * @generated from protobuf field: uint64 complete_code = 11; - */ - complete_code: bigint; - /** - * Completed (or "linked") code percent - * - * @generated from protobuf field: float complete_code_percent = 12; - */ - complete_code_percent: number; - /** - * Completed (or "linked") data size in bytes - * - * @generated from protobuf field: uint64 complete_data = 13; - */ - complete_data: bigint; - /** - * Completed (or "linked") data percent - * - * @generated from protobuf field: float complete_data_percent = 14; - */ - complete_data_percent: number; - /** - * Total number of units - * - * @generated from protobuf field: uint32 total_units = 15; - */ - total_units: number; - /** - * Completed (or "linked") units - * - * @generated from protobuf field: uint32 complete_units = 16; - */ - complete_units: number; -} -/** - * Project progress report - * - * @generated from protobuf message objdiff.report.Report - */ -export interface Report { - /** - * Overall progress info - * - * @generated from protobuf field: objdiff.report.Measures measures = 1; - */ - measures?: Measures; - /** - * Units within this report - * - * @generated from protobuf field: repeated objdiff.report.ReportUnit units = 2; - */ - units: ReportUnit[]; - /** - * Report version - * - * @generated from protobuf field: uint32 version = 3; - */ - version: number; - /** - * Progress categories - * - * @generated from protobuf field: repeated objdiff.report.ReportCategory categories = 4; - */ - categories: ReportCategory[]; -} -/** - * @generated from protobuf message objdiff.report.ReportCategory - */ -export interface ReportCategory { - /** - * The ID of the category - * - * @generated from protobuf field: string id = 1; - */ - id: string; - /** - * The name of the category - * - * @generated from protobuf field: string name = 2; - */ - name: string; - /** - * Progress info for this category - * - * @generated from protobuf field: objdiff.report.Measures measures = 3; - */ - measures?: Measures; -} -/** - * A unit of the report (usually a translation unit) - * - * @generated from protobuf message objdiff.report.ReportUnit - */ -export interface ReportUnit { - /** - * The name of the unit - * - * @generated from protobuf field: string name = 1; - */ - name: string; - /** - * Progress info for this unit - * - * @generated from protobuf field: objdiff.report.Measures measures = 2; - */ - measures?: Measures; - /** - * Sections within this unit - * - * @generated from protobuf field: repeated objdiff.report.ReportItem sections = 3; - */ - sections: ReportItem[]; - /** - * Functions within this unit - * - * @generated from protobuf field: repeated objdiff.report.ReportItem functions = 4; - */ - functions: ReportItem[]; - /** - * Extra metadata for this unit - * - * @generated from protobuf field: optional objdiff.report.ReportUnitMetadata metadata = 5; - */ - metadata?: ReportUnitMetadata; -} -/** - * Extra metadata for a unit - * - * @generated from protobuf message objdiff.report.ReportUnitMetadata - */ -export interface ReportUnitMetadata { - /** - * Whether this unit is marked as complete (or "linked") - * - * @generated from protobuf field: optional bool complete = 1; - */ - complete?: boolean; - /** - * The name of the module this unit belongs to - * - * @generated from protobuf field: optional string module_name = 2; - */ - module_name?: string; - /** - * The ID of the module this unit belongs to - * - * @generated from protobuf field: optional uint32 module_id = 3; - */ - module_id?: number; - /** - * The path to the source file of this unit - * - * @generated from protobuf field: optional string source_path = 4; - */ - source_path?: string; - /** - * Progress categories for this unit - * - * @generated from protobuf field: repeated string progress_categories = 5; - */ - progress_categories: string[]; - /** - * Whether this unit is automatically generated (not user-provided) - * - * @generated from protobuf field: optional bool auto_generated = 6; - */ - auto_generated?: boolean; -} -/** - * A section or function within a unit - * - * @generated from protobuf message objdiff.report.ReportItem - */ -export interface ReportItem { - /** - * The name of the item - * - * @generated from protobuf field: string name = 1; - */ - name: string; - /** - * The size of the item in bytes - * - * @generated from protobuf field: uint64 size = 2; - */ - size: bigint; - /** - * The overall match percent for this item - * - * @generated from protobuf field: float fuzzy_match_percent = 3; - */ - fuzzy_match_percent: number; - /** - * Extra metadata for this item - * - * @generated from protobuf field: optional objdiff.report.ReportItemMetadata metadata = 4; - */ - metadata?: ReportItemMetadata; -} -/** - * Extra metadata for an item - * - * @generated from protobuf message objdiff.report.ReportItemMetadata - */ -export interface ReportItemMetadata { - /** - * The demangled name of the function - * - * @generated from protobuf field: optional string demangled_name = 1; - */ - demangled_name?: string; - /** - * The virtual address of the function or section - * - * @generated from protobuf field: optional uint64 virtual_address = 2; - */ - virtual_address?: bigint; -} -/** - * A pair of reports to compare and generate changes - * - * @generated from protobuf message objdiff.report.ChangesInput - */ -export interface ChangesInput { - /** - * The previous report - * - * @generated from protobuf field: objdiff.report.Report from = 1; - */ - from?: Report; - /** - * The current report - * - * @generated from protobuf field: objdiff.report.Report to = 2; - */ - to?: Report; -} -/** - * Changes between two reports - * - * @generated from protobuf message objdiff.report.Changes - */ -export interface Changes { - /** - * The progress info for the previous report - * - * @generated from protobuf field: objdiff.report.Measures from = 1; - */ - from?: Measures; - /** - * The progress info for the current report - * - * @generated from protobuf field: objdiff.report.Measures to = 2; - */ - to?: Measures; - /** - * Units that changed - * - * @generated from protobuf field: repeated objdiff.report.ChangeUnit units = 3; - */ - units: ChangeUnit[]; -} -/** - * A changed unit - * - * @generated from protobuf message objdiff.report.ChangeUnit - */ -export interface ChangeUnit { - /** - * The name of the unit - * - * @generated from protobuf field: string name = 1; - */ - name: string; - /** - * The previous progress info (omitted if new) - * - * @generated from protobuf field: optional objdiff.report.Measures from = 2; - */ - from?: Measures; - /** - * The current progress info (omitted if removed) - * - * @generated from protobuf field: optional objdiff.report.Measures to = 3; - */ - to?: Measures; - /** - * Sections that changed - * - * @generated from protobuf field: repeated objdiff.report.ChangeItem sections = 4; - */ - sections: ChangeItem[]; - /** - * Functions that changed - * - * @generated from protobuf field: repeated objdiff.report.ChangeItem functions = 5; - */ - functions: ChangeItem[]; - /** - * Extra metadata for this unit - * - * @generated from protobuf field: optional objdiff.report.ReportUnitMetadata metadata = 6; - */ - metadata?: ReportUnitMetadata; -} -/** - * A changed section or function - * - * @generated from protobuf message objdiff.report.ChangeItem - */ -export interface ChangeItem { - /** - * The name of the item - * - * @generated from protobuf field: string name = 1; - */ - name: string; - /** - * The previous progress info (omitted if new) - * - * @generated from protobuf field: optional objdiff.report.ChangeItemInfo from = 2; - */ - from?: ChangeItemInfo; - /** - * The current progress info (omitted if removed) - * - * @generated from protobuf field: optional objdiff.report.ChangeItemInfo to = 3; - */ - to?: ChangeItemInfo; - /** - * Extra metadata for this item - * - * @generated from protobuf field: optional objdiff.report.ReportItemMetadata metadata = 4; - */ - metadata?: ReportItemMetadata; -} -/** - * Progress info for a section or function - * - * @generated from protobuf message objdiff.report.ChangeItemInfo - */ -export interface ChangeItemInfo { - /** - * The overall match percent for this item - * - * @generated from protobuf field: float fuzzy_match_percent = 1; - */ - fuzzy_match_percent: number; - /** - * The size of the item in bytes - * - * @generated from protobuf field: uint64 size = 2; - */ - size: bigint; -} -// @generated message type with reflection information, may provide speed optimized methods -class Measures$Type extends MessageType { - constructor() { - super('objdiff.report.Measures', [ - { - no: 1, - name: 'fuzzy_match_percent', - kind: 'scalar', - localName: 'fuzzy_match_percent', - T: 2 /*ScalarType.FLOAT*/, - }, - { - no: 2, - name: 'total_code', - kind: 'scalar', - localName: 'total_code', - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - { - no: 3, - name: 'matched_code', - kind: 'scalar', - localName: 'matched_code', - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - { - no: 4, - name: 'matched_code_percent', - kind: 'scalar', - localName: 'matched_code_percent', - T: 2 /*ScalarType.FLOAT*/, - }, - { - no: 5, - name: 'total_data', - kind: 'scalar', - localName: 'total_data', - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - { - no: 6, - name: 'matched_data', - kind: 'scalar', - localName: 'matched_data', - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - { - no: 7, - name: 'matched_data_percent', - kind: 'scalar', - localName: 'matched_data_percent', - T: 2 /*ScalarType.FLOAT*/, - }, - { - no: 8, - name: 'total_functions', - kind: 'scalar', - localName: 'total_functions', - T: 13 /*ScalarType.UINT32*/, - }, - { - no: 9, - name: 'matched_functions', - kind: 'scalar', - localName: 'matched_functions', - T: 13 /*ScalarType.UINT32*/, - }, - { - no: 10, - name: 'matched_functions_percent', - kind: 'scalar', - localName: 'matched_functions_percent', - T: 2 /*ScalarType.FLOAT*/, - }, - { - no: 11, - name: 'complete_code', - kind: 'scalar', - localName: 'complete_code', - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - { - no: 12, - name: 'complete_code_percent', - kind: 'scalar', - localName: 'complete_code_percent', - T: 2 /*ScalarType.FLOAT*/, - }, - { - no: 13, - name: 'complete_data', - kind: 'scalar', - localName: 'complete_data', - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - { - no: 14, - name: 'complete_data_percent', - kind: 'scalar', - localName: 'complete_data_percent', - T: 2 /*ScalarType.FLOAT*/, - }, - { - no: 15, - name: 'total_units', - kind: 'scalar', - localName: 'total_units', - T: 13 /*ScalarType.UINT32*/, - }, - { - no: 16, - name: 'complete_units', - kind: 'scalar', - localName: 'complete_units', - T: 13 /*ScalarType.UINT32*/, - }, - ]); - } - create(value?: PartialMessage): Measures { - const message = globalThis.Object.create(this.messagePrototype!); - message.fuzzy_match_percent = 0; - message.total_code = 0n; - message.matched_code = 0n; - message.matched_code_percent = 0; - message.total_data = 0n; - message.matched_data = 0n; - message.matched_data_percent = 0; - message.total_functions = 0; - message.matched_functions = 0; - message.matched_functions_percent = 0; - message.complete_code = 0n; - message.complete_code_percent = 0; - message.complete_data = 0n; - message.complete_data_percent = 0; - message.total_units = 0; - message.complete_units = 0; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: Measures, - ): Measures { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* float fuzzy_match_percent */ 1: - message.fuzzy_match_percent = reader.float(); - break; - case /* uint64 total_code */ 2: - message.total_code = reader.uint64().toBigInt(); - break; - case /* uint64 matched_code */ 3: - message.matched_code = reader.uint64().toBigInt(); - break; - case /* float matched_code_percent */ 4: - message.matched_code_percent = reader.float(); - break; - case /* uint64 total_data */ 5: - message.total_data = reader.uint64().toBigInt(); - break; - case /* uint64 matched_data */ 6: - message.matched_data = reader.uint64().toBigInt(); - break; - case /* float matched_data_percent */ 7: - message.matched_data_percent = reader.float(); - break; - case /* uint32 total_functions */ 8: - message.total_functions = reader.uint32(); - break; - case /* uint32 matched_functions */ 9: - message.matched_functions = reader.uint32(); - break; - case /* float matched_functions_percent */ 10: - message.matched_functions_percent = reader.float(); - break; - case /* uint64 complete_code */ 11: - message.complete_code = reader.uint64().toBigInt(); - break; - case /* float complete_code_percent */ 12: - message.complete_code_percent = reader.float(); - break; - case /* uint64 complete_data */ 13: - message.complete_data = reader.uint64().toBigInt(); - break; - case /* float complete_data_percent */ 14: - message.complete_data_percent = reader.float(); - break; - case /* uint32 total_units */ 15: - message.total_units = reader.uint32(); - break; - case /* uint32 complete_units */ 16: - message.complete_units = reader.uint32(); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: Measures, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* float fuzzy_match_percent = 1; */ - if (message.fuzzy_match_percent !== 0) - writer.tag(1, WireType.Bit32).float(message.fuzzy_match_percent); - /* uint64 total_code = 2; */ - if (message.total_code !== 0n) - writer.tag(2, WireType.Varint).uint64(message.total_code); - /* uint64 matched_code = 3; */ - if (message.matched_code !== 0n) - writer.tag(3, WireType.Varint).uint64(message.matched_code); - /* float matched_code_percent = 4; */ - if (message.matched_code_percent !== 0) - writer.tag(4, WireType.Bit32).float(message.matched_code_percent); - /* uint64 total_data = 5; */ - if (message.total_data !== 0n) - writer.tag(5, WireType.Varint).uint64(message.total_data); - /* uint64 matched_data = 6; */ - if (message.matched_data !== 0n) - writer.tag(6, WireType.Varint).uint64(message.matched_data); - /* float matched_data_percent = 7; */ - if (message.matched_data_percent !== 0) - writer.tag(7, WireType.Bit32).float(message.matched_data_percent); - /* uint32 total_functions = 8; */ - if (message.total_functions !== 0) - writer.tag(8, WireType.Varint).uint32(message.total_functions); - /* uint32 matched_functions = 9; */ - if (message.matched_functions !== 0) - writer.tag(9, WireType.Varint).uint32(message.matched_functions); - /* float matched_functions_percent = 10; */ - if (message.matched_functions_percent !== 0) - writer.tag(10, WireType.Bit32).float(message.matched_functions_percent); - /* uint64 complete_code = 11; */ - if (message.complete_code !== 0n) - writer.tag(11, WireType.Varint).uint64(message.complete_code); - /* float complete_code_percent = 12; */ - if (message.complete_code_percent !== 0) - writer.tag(12, WireType.Bit32).float(message.complete_code_percent); - /* uint64 complete_data = 13; */ - if (message.complete_data !== 0n) - writer.tag(13, WireType.Varint).uint64(message.complete_data); - /* float complete_data_percent = 14; */ - if (message.complete_data_percent !== 0) - writer.tag(14, WireType.Bit32).float(message.complete_data_percent); - /* uint32 total_units = 15; */ - if (message.total_units !== 0) - writer.tag(15, WireType.Varint).uint32(message.total_units); - /* uint32 complete_units = 16; */ - if (message.complete_units !== 0) - writer.tag(16, WireType.Varint).uint32(message.complete_units); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.Measures - */ -export const Measures = new Measures$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class Report$Type extends MessageType { - constructor() { - super('objdiff.report.Report', [ - { no: 1, name: 'measures', kind: 'message', T: () => Measures }, - { - no: 2, - name: 'units', - kind: 'message', - repeat: 1 /*RepeatType.PACKED*/, - T: () => ReportUnit, - }, - { no: 3, name: 'version', kind: 'scalar', T: 13 /*ScalarType.UINT32*/ }, - { - no: 4, - name: 'categories', - kind: 'message', - repeat: 1 /*RepeatType.PACKED*/, - T: () => ReportCategory, - }, - ]); - } - create(value?: PartialMessage): Report { - const message = globalThis.Object.create(this.messagePrototype!); - message.units = []; - message.version = 0; - message.categories = []; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: Report, - ): Report { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* objdiff.report.Measures measures */ 1: - message.measures = Measures.internalBinaryRead( - reader, - reader.uint32(), - options, - message.measures, - ); - break; - case /* repeated objdiff.report.ReportUnit units */ 2: - message.units.push( - ReportUnit.internalBinaryRead(reader, reader.uint32(), options), - ); - break; - case /* uint32 version */ 3: - message.version = reader.uint32(); - break; - case /* repeated objdiff.report.ReportCategory categories */ 4: - message.categories.push( - ReportCategory.internalBinaryRead(reader, reader.uint32(), options), - ); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: Report, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* objdiff.report.Measures measures = 1; */ - if (message.measures) - Measures.internalBinaryWrite( - message.measures, - writer.tag(1, WireType.LengthDelimited).fork(), - options, - ).join(); - /* repeated objdiff.report.ReportUnit units = 2; */ - for (let i = 0; i < message.units.length; i++) - ReportUnit.internalBinaryWrite( - message.units[i], - writer.tag(2, WireType.LengthDelimited).fork(), - options, - ).join(); - /* uint32 version = 3; */ - if (message.version !== 0) - writer.tag(3, WireType.Varint).uint32(message.version); - /* repeated objdiff.report.ReportCategory categories = 4; */ - for (let i = 0; i < message.categories.length; i++) - ReportCategory.internalBinaryWrite( - message.categories[i], - writer.tag(4, WireType.LengthDelimited).fork(), - options, - ).join(); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.Report - */ -export const Report = new Report$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ReportCategory$Type extends MessageType { - constructor() { - super('objdiff.report.ReportCategory', [ - { no: 1, name: 'id', kind: 'scalar', T: 9 /*ScalarType.STRING*/ }, - { no: 2, name: 'name', kind: 'scalar', T: 9 /*ScalarType.STRING*/ }, - { no: 3, name: 'measures', kind: 'message', T: () => Measures }, - ]); - } - create(value?: PartialMessage): ReportCategory { - const message = globalThis.Object.create(this.messagePrototype!); - message.id = ''; - message.name = ''; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ReportCategory, - ): ReportCategory { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* string id */ 1: - message.id = reader.string(); - break; - case /* string name */ 2: - message.name = reader.string(); - break; - case /* objdiff.report.Measures measures */ 3: - message.measures = Measures.internalBinaryRead( - reader, - reader.uint32(), - options, - message.measures, - ); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ReportCategory, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* string id = 1; */ - if (message.id !== '') - writer.tag(1, WireType.LengthDelimited).string(message.id); - /* string name = 2; */ - if (message.name !== '') - writer.tag(2, WireType.LengthDelimited).string(message.name); - /* objdiff.report.Measures measures = 3; */ - if (message.measures) - Measures.internalBinaryWrite( - message.measures, - writer.tag(3, WireType.LengthDelimited).fork(), - options, - ).join(); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ReportCategory - */ -export const ReportCategory = new ReportCategory$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ReportUnit$Type extends MessageType { - constructor() { - super('objdiff.report.ReportUnit', [ - { no: 1, name: 'name', kind: 'scalar', T: 9 /*ScalarType.STRING*/ }, - { no: 2, name: 'measures', kind: 'message', T: () => Measures }, - { - no: 3, - name: 'sections', - kind: 'message', - repeat: 1 /*RepeatType.PACKED*/, - T: () => ReportItem, - }, - { - no: 4, - name: 'functions', - kind: 'message', - repeat: 1 /*RepeatType.PACKED*/, - T: () => ReportItem, - }, - { no: 5, name: 'metadata', kind: 'message', T: () => ReportUnitMetadata }, - ]); - } - create(value?: PartialMessage): ReportUnit { - const message = globalThis.Object.create(this.messagePrototype!); - message.name = ''; - message.sections = []; - message.functions = []; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ReportUnit, - ): ReportUnit { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* string name */ 1: - message.name = reader.string(); - break; - case /* objdiff.report.Measures measures */ 2: - message.measures = Measures.internalBinaryRead( - reader, - reader.uint32(), - options, - message.measures, - ); - break; - case /* repeated objdiff.report.ReportItem sections */ 3: - message.sections.push( - ReportItem.internalBinaryRead(reader, reader.uint32(), options), - ); - break; - case /* repeated objdiff.report.ReportItem functions */ 4: - message.functions.push( - ReportItem.internalBinaryRead(reader, reader.uint32(), options), - ); - break; - case /* optional objdiff.report.ReportUnitMetadata metadata */ 5: - message.metadata = ReportUnitMetadata.internalBinaryRead( - reader, - reader.uint32(), - options, - message.metadata, - ); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ReportUnit, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* string name = 1; */ - if (message.name !== '') - writer.tag(1, WireType.LengthDelimited).string(message.name); - /* objdiff.report.Measures measures = 2; */ - if (message.measures) - Measures.internalBinaryWrite( - message.measures, - writer.tag(2, WireType.LengthDelimited).fork(), - options, - ).join(); - /* repeated objdiff.report.ReportItem sections = 3; */ - for (let i = 0; i < message.sections.length; i++) - ReportItem.internalBinaryWrite( - message.sections[i], - writer.tag(3, WireType.LengthDelimited).fork(), - options, - ).join(); - /* repeated objdiff.report.ReportItem functions = 4; */ - for (let i = 0; i < message.functions.length; i++) - ReportItem.internalBinaryWrite( - message.functions[i], - writer.tag(4, WireType.LengthDelimited).fork(), - options, - ).join(); - /* optional objdiff.report.ReportUnitMetadata metadata = 5; */ - if (message.metadata) - ReportUnitMetadata.internalBinaryWrite( - message.metadata, - writer.tag(5, WireType.LengthDelimited).fork(), - options, - ).join(); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ReportUnit - */ -export const ReportUnit = new ReportUnit$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ReportUnitMetadata$Type extends MessageType { - constructor() { - super('objdiff.report.ReportUnitMetadata', [ - { - no: 1, - name: 'complete', - kind: 'scalar', - opt: true, - T: 8 /*ScalarType.BOOL*/, - }, - { - no: 2, - name: 'module_name', - kind: 'scalar', - localName: 'module_name', - opt: true, - T: 9 /*ScalarType.STRING*/, - }, - { - no: 3, - name: 'module_id', - kind: 'scalar', - localName: 'module_id', - opt: true, - T: 13 /*ScalarType.UINT32*/, - }, - { - no: 4, - name: 'source_path', - kind: 'scalar', - localName: 'source_path', - opt: true, - T: 9 /*ScalarType.STRING*/, - }, - { - no: 5, - name: 'progress_categories', - kind: 'scalar', - localName: 'progress_categories', - repeat: 2 /*RepeatType.UNPACKED*/, - T: 9 /*ScalarType.STRING*/, - }, - { - no: 6, - name: 'auto_generated', - kind: 'scalar', - localName: 'auto_generated', - opt: true, - T: 8 /*ScalarType.BOOL*/, - }, - ]); - } - create(value?: PartialMessage): ReportUnitMetadata { - const message = globalThis.Object.create(this.messagePrototype!); - message.progress_categories = []; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ReportUnitMetadata, - ): ReportUnitMetadata { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* optional bool complete */ 1: - message.complete = reader.bool(); - break; - case /* optional string module_name */ 2: - message.module_name = reader.string(); - break; - case /* optional uint32 module_id */ 3: - message.module_id = reader.uint32(); - break; - case /* optional string source_path */ 4: - message.source_path = reader.string(); - break; - case /* repeated string progress_categories */ 5: - message.progress_categories.push(reader.string()); - break; - case /* optional bool auto_generated */ 6: - message.auto_generated = reader.bool(); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ReportUnitMetadata, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* optional bool complete = 1; */ - if (message.complete !== undefined) - writer.tag(1, WireType.Varint).bool(message.complete); - /* optional string module_name = 2; */ - if (message.module_name !== undefined) - writer.tag(2, WireType.LengthDelimited).string(message.module_name); - /* optional uint32 module_id = 3; */ - if (message.module_id !== undefined) - writer.tag(3, WireType.Varint).uint32(message.module_id); - /* optional string source_path = 4; */ - if (message.source_path !== undefined) - writer.tag(4, WireType.LengthDelimited).string(message.source_path); - /* repeated string progress_categories = 5; */ - for (let i = 0; i < message.progress_categories.length; i++) - writer - .tag(5, WireType.LengthDelimited) - .string(message.progress_categories[i]); - /* optional bool auto_generated = 6; */ - if (message.auto_generated !== undefined) - writer.tag(6, WireType.Varint).bool(message.auto_generated); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ReportUnitMetadata - */ -export const ReportUnitMetadata = new ReportUnitMetadata$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ReportItem$Type extends MessageType { - constructor() { - super('objdiff.report.ReportItem', [ - { no: 1, name: 'name', kind: 'scalar', T: 9 /*ScalarType.STRING*/ }, - { - no: 2, - name: 'size', - kind: 'scalar', - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - { - no: 3, - name: 'fuzzy_match_percent', - kind: 'scalar', - localName: 'fuzzy_match_percent', - T: 2 /*ScalarType.FLOAT*/, - }, - { no: 4, name: 'metadata', kind: 'message', T: () => ReportItemMetadata }, - ]); - } - create(value?: PartialMessage): ReportItem { - const message = globalThis.Object.create(this.messagePrototype!); - message.name = ''; - message.size = 0n; - message.fuzzy_match_percent = 0; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ReportItem, - ): ReportItem { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* string name */ 1: - message.name = reader.string(); - break; - case /* uint64 size */ 2: - message.size = reader.uint64().toBigInt(); - break; - case /* float fuzzy_match_percent */ 3: - message.fuzzy_match_percent = reader.float(); - break; - case /* optional objdiff.report.ReportItemMetadata metadata */ 4: - message.metadata = ReportItemMetadata.internalBinaryRead( - reader, - reader.uint32(), - options, - message.metadata, - ); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ReportItem, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* string name = 1; */ - if (message.name !== '') - writer.tag(1, WireType.LengthDelimited).string(message.name); - /* uint64 size = 2; */ - if (message.size !== 0n) - writer.tag(2, WireType.Varint).uint64(message.size); - /* float fuzzy_match_percent = 3; */ - if (message.fuzzy_match_percent !== 0) - writer.tag(3, WireType.Bit32).float(message.fuzzy_match_percent); - /* optional objdiff.report.ReportItemMetadata metadata = 4; */ - if (message.metadata) - ReportItemMetadata.internalBinaryWrite( - message.metadata, - writer.tag(4, WireType.LengthDelimited).fork(), - options, - ).join(); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ReportItem - */ -export const ReportItem = new ReportItem$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ReportItemMetadata$Type extends MessageType { - constructor() { - super('objdiff.report.ReportItemMetadata', [ - { - no: 1, - name: 'demangled_name', - kind: 'scalar', - localName: 'demangled_name', - opt: true, - T: 9 /*ScalarType.STRING*/, - }, - { - no: 2, - name: 'virtual_address', - kind: 'scalar', - localName: 'virtual_address', - opt: true, - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - ]); - } - create(value?: PartialMessage): ReportItemMetadata { - const message = globalThis.Object.create(this.messagePrototype!); - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ReportItemMetadata, - ): ReportItemMetadata { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* optional string demangled_name */ 1: - message.demangled_name = reader.string(); - break; - case /* optional uint64 virtual_address */ 2: - message.virtual_address = reader.uint64().toBigInt(); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ReportItemMetadata, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* optional string demangled_name = 1; */ - if (message.demangled_name !== undefined) - writer.tag(1, WireType.LengthDelimited).string(message.demangled_name); - /* optional uint64 virtual_address = 2; */ - if (message.virtual_address !== undefined) - writer.tag(2, WireType.Varint).uint64(message.virtual_address); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ReportItemMetadata - */ -export const ReportItemMetadata = new ReportItemMetadata$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ChangesInput$Type extends MessageType { - constructor() { - super('objdiff.report.ChangesInput', [ - { no: 1, name: 'from', kind: 'message', T: () => Report }, - { no: 2, name: 'to', kind: 'message', T: () => Report }, - ]); - } - create(value?: PartialMessage): ChangesInput { - const message = globalThis.Object.create(this.messagePrototype!); - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ChangesInput, - ): ChangesInput { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* objdiff.report.Report from */ 1: - message.from = Report.internalBinaryRead( - reader, - reader.uint32(), - options, - message.from, - ); - break; - case /* objdiff.report.Report to */ 2: - message.to = Report.internalBinaryRead( - reader, - reader.uint32(), - options, - message.to, - ); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ChangesInput, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* objdiff.report.Report from = 1; */ - if (message.from) - Report.internalBinaryWrite( - message.from, - writer.tag(1, WireType.LengthDelimited).fork(), - options, - ).join(); - /* objdiff.report.Report to = 2; */ - if (message.to) - Report.internalBinaryWrite( - message.to, - writer.tag(2, WireType.LengthDelimited).fork(), - options, - ).join(); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ChangesInput - */ -export const ChangesInput = new ChangesInput$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class Changes$Type extends MessageType { - constructor() { - super('objdiff.report.Changes', [ - { no: 1, name: 'from', kind: 'message', T: () => Measures }, - { no: 2, name: 'to', kind: 'message', T: () => Measures }, - { - no: 3, - name: 'units', - kind: 'message', - repeat: 1 /*RepeatType.PACKED*/, - T: () => ChangeUnit, - }, - ]); - } - create(value?: PartialMessage): Changes { - const message = globalThis.Object.create(this.messagePrototype!); - message.units = []; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: Changes, - ): Changes { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* objdiff.report.Measures from */ 1: - message.from = Measures.internalBinaryRead( - reader, - reader.uint32(), - options, - message.from, - ); - break; - case /* objdiff.report.Measures to */ 2: - message.to = Measures.internalBinaryRead( - reader, - reader.uint32(), - options, - message.to, - ); - break; - case /* repeated objdiff.report.ChangeUnit units */ 3: - message.units.push( - ChangeUnit.internalBinaryRead(reader, reader.uint32(), options), - ); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: Changes, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* objdiff.report.Measures from = 1; */ - if (message.from) - Measures.internalBinaryWrite( - message.from, - writer.tag(1, WireType.LengthDelimited).fork(), - options, - ).join(); - /* objdiff.report.Measures to = 2; */ - if (message.to) - Measures.internalBinaryWrite( - message.to, - writer.tag(2, WireType.LengthDelimited).fork(), - options, - ).join(); - /* repeated objdiff.report.ChangeUnit units = 3; */ - for (let i = 0; i < message.units.length; i++) - ChangeUnit.internalBinaryWrite( - message.units[i], - writer.tag(3, WireType.LengthDelimited).fork(), - options, - ).join(); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.Changes - */ -export const Changes = new Changes$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ChangeUnit$Type extends MessageType { - constructor() { - super('objdiff.report.ChangeUnit', [ - { no: 1, name: 'name', kind: 'scalar', T: 9 /*ScalarType.STRING*/ }, - { no: 2, name: 'from', kind: 'message', T: () => Measures }, - { no: 3, name: 'to', kind: 'message', T: () => Measures }, - { - no: 4, - name: 'sections', - kind: 'message', - repeat: 1 /*RepeatType.PACKED*/, - T: () => ChangeItem, - }, - { - no: 5, - name: 'functions', - kind: 'message', - repeat: 1 /*RepeatType.PACKED*/, - T: () => ChangeItem, - }, - { no: 6, name: 'metadata', kind: 'message', T: () => ReportUnitMetadata }, - ]); - } - create(value?: PartialMessage): ChangeUnit { - const message = globalThis.Object.create(this.messagePrototype!); - message.name = ''; - message.sections = []; - message.functions = []; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ChangeUnit, - ): ChangeUnit { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* string name */ 1: - message.name = reader.string(); - break; - case /* optional objdiff.report.Measures from */ 2: - message.from = Measures.internalBinaryRead( - reader, - reader.uint32(), - options, - message.from, - ); - break; - case /* optional objdiff.report.Measures to */ 3: - message.to = Measures.internalBinaryRead( - reader, - reader.uint32(), - options, - message.to, - ); - break; - case /* repeated objdiff.report.ChangeItem sections */ 4: - message.sections.push( - ChangeItem.internalBinaryRead(reader, reader.uint32(), options), - ); - break; - case /* repeated objdiff.report.ChangeItem functions */ 5: - message.functions.push( - ChangeItem.internalBinaryRead(reader, reader.uint32(), options), - ); - break; - case /* optional objdiff.report.ReportUnitMetadata metadata */ 6: - message.metadata = ReportUnitMetadata.internalBinaryRead( - reader, - reader.uint32(), - options, - message.metadata, - ); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ChangeUnit, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* string name = 1; */ - if (message.name !== '') - writer.tag(1, WireType.LengthDelimited).string(message.name); - /* optional objdiff.report.Measures from = 2; */ - if (message.from) - Measures.internalBinaryWrite( - message.from, - writer.tag(2, WireType.LengthDelimited).fork(), - options, - ).join(); - /* optional objdiff.report.Measures to = 3; */ - if (message.to) - Measures.internalBinaryWrite( - message.to, - writer.tag(3, WireType.LengthDelimited).fork(), - options, - ).join(); - /* repeated objdiff.report.ChangeItem sections = 4; */ - for (let i = 0; i < message.sections.length; i++) - ChangeItem.internalBinaryWrite( - message.sections[i], - writer.tag(4, WireType.LengthDelimited).fork(), - options, - ).join(); - /* repeated objdiff.report.ChangeItem functions = 5; */ - for (let i = 0; i < message.functions.length; i++) - ChangeItem.internalBinaryWrite( - message.functions[i], - writer.tag(5, WireType.LengthDelimited).fork(), - options, - ).join(); - /* optional objdiff.report.ReportUnitMetadata metadata = 6; */ - if (message.metadata) - ReportUnitMetadata.internalBinaryWrite( - message.metadata, - writer.tag(6, WireType.LengthDelimited).fork(), - options, - ).join(); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ChangeUnit - */ -export const ChangeUnit = new ChangeUnit$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ChangeItem$Type extends MessageType { - constructor() { - super('objdiff.report.ChangeItem', [ - { no: 1, name: 'name', kind: 'scalar', T: 9 /*ScalarType.STRING*/ }, - { no: 2, name: 'from', kind: 'message', T: () => ChangeItemInfo }, - { no: 3, name: 'to', kind: 'message', T: () => ChangeItemInfo }, - { no: 4, name: 'metadata', kind: 'message', T: () => ReportItemMetadata }, - ]); - } - create(value?: PartialMessage): ChangeItem { - const message = globalThis.Object.create(this.messagePrototype!); - message.name = ''; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ChangeItem, - ): ChangeItem { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* string name */ 1: - message.name = reader.string(); - break; - case /* optional objdiff.report.ChangeItemInfo from */ 2: - message.from = ChangeItemInfo.internalBinaryRead( - reader, - reader.uint32(), - options, - message.from, - ); - break; - case /* optional objdiff.report.ChangeItemInfo to */ 3: - message.to = ChangeItemInfo.internalBinaryRead( - reader, - reader.uint32(), - options, - message.to, - ); - break; - case /* optional objdiff.report.ReportItemMetadata metadata */ 4: - message.metadata = ReportItemMetadata.internalBinaryRead( - reader, - reader.uint32(), - options, - message.metadata, - ); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ChangeItem, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* string name = 1; */ - if (message.name !== '') - writer.tag(1, WireType.LengthDelimited).string(message.name); - /* optional objdiff.report.ChangeItemInfo from = 2; */ - if (message.from) - ChangeItemInfo.internalBinaryWrite( - message.from, - writer.tag(2, WireType.LengthDelimited).fork(), - options, - ).join(); - /* optional objdiff.report.ChangeItemInfo to = 3; */ - if (message.to) - ChangeItemInfo.internalBinaryWrite( - message.to, - writer.tag(3, WireType.LengthDelimited).fork(), - options, - ).join(); - /* optional objdiff.report.ReportItemMetadata metadata = 4; */ - if (message.metadata) - ReportItemMetadata.internalBinaryWrite( - message.metadata, - writer.tag(4, WireType.LengthDelimited).fork(), - options, - ).join(); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ChangeItem - */ -export const ChangeItem = new ChangeItem$Type(); -// @generated message type with reflection information, may provide speed optimized methods -class ChangeItemInfo$Type extends MessageType { - constructor() { - super('objdiff.report.ChangeItemInfo', [ - { - no: 1, - name: 'fuzzy_match_percent', - kind: 'scalar', - localName: 'fuzzy_match_percent', - T: 2 /*ScalarType.FLOAT*/, - }, - { - no: 2, - name: 'size', - kind: 'scalar', - T: 4 /*ScalarType.UINT64*/, - L: 0 /*LongType.BIGINT*/, - }, - ]); - } - create(value?: PartialMessage): ChangeItemInfo { - const message = globalThis.Object.create(this.messagePrototype!); - message.fuzzy_match_percent = 0; - message.size = 0n; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead( - reader: IBinaryReader, - length: number, - options: BinaryReadOptions, - target?: ChangeItemInfo, - ): ChangeItemInfo { - let message = target ?? this.create(), - end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* float fuzzy_match_percent */ 1: - message.fuzzy_match_percent = reader.float(); - break; - case /* uint64 size */ 2: - message.size = reader.uint64().toBigInt(); - break; - default: - let u = options.readUnknownField; - if (u === 'throw') - throw new globalThis.Error( - `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`, - ); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)( - this.typeName, - message, - fieldNo, - wireType, - d, - ); - } - } - return message; - } - internalBinaryWrite( - message: ChangeItemInfo, - writer: IBinaryWriter, - options: BinaryWriteOptions, - ): IBinaryWriter { - /* float fuzzy_match_percent = 1; */ - if (message.fuzzy_match_percent !== 0) - writer.tag(1, WireType.Bit32).float(message.fuzzy_match_percent); - /* uint64 size = 2; */ - if (message.size !== 0n) - writer.tag(2, WireType.Varint).uint64(message.size); - let u = options.writeUnknownFields; - if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)( - this.typeName, - message, - writer, - ); - return writer; - } -} -/** - * @generated MessageType for protobuf message objdiff.report.ChangeItemInfo - */ -export const ChangeItemInfo = new ChangeItemInfo$Type(); diff --git a/package.json b/package.json index ab8630c..4c08b3b 100644 --- a/package.json +++ b/package.json @@ -39,14 +39,30 @@ "engines": { "vscode": "^1.96.0" }, - "browserslist": ["chrome 128"], - "categories": ["Other"], - "activationEvents": ["*"], + "browserslist": [ + "chrome 128" + ], + "categories": [ + "Other" + ], + "activationEvents": [ + "*" + ], "contributes": { "commands": [ { "command": "objdiff.build", "title": "objdiff: build" + }, + { + "command": "objdiff.copySymbolName", + "title": "Copy name", + "enablement": "webviewId == 'objdiff' && contextType == 'symbol'" + }, + { + "command": "objdiff.copySymbolDemangledName", + "title": "Copy demangled name", + "enablement": "webviewId == 'objdiff' && contextType == 'symbol' && symbolDemangledName" } ], "configuration": { @@ -59,6 +75,23 @@ } } }, + "menus": { + "webview/context": [ + { + "command": "objdiff.copySymbolName", + "when": "webviewId == 'objdiff' && contextType == 'symbol'" + }, + { + "command": "objdiff.copySymbolDemangledName", + "when": "webviewId == 'objdiff' && contextType == 'symbol'" + } + ] + }, + "taskDefinitions": [ + { + "type": "objdiff" + } + ], "viewsContainers": { "panel": [ { @@ -82,11 +115,6 @@ "view": "objdiff", "contents": "Loading..." } - ], - "taskDefinitions": [ - { - "type": "objdiff" - } ] } } diff --git a/rsbuild.config.ts b/rsbuild.config.ts index 593247c..c111d92 100644 --- a/rsbuild.config.ts +++ b/rsbuild.config.ts @@ -47,6 +47,7 @@ export default defineConfig({ html: { inject: 'body', scriptLoading: 'blocking', + title: 'objdiff', }, plugins: [ pluginReact({ diff --git a/gen/diff_pb.ts b/shared/gen/diff_pb.ts similarity index 92% rename from gen/diff_pb.ts rename to shared/gen/diff_pb.ts index 21014dd..3758039 100644 --- a/gen/diff_pb.ts +++ b/shared/gen/diff_pb.ts @@ -296,9 +296,22 @@ export interface InstructionBranchTo { branch_index: number; } /** - * @generated from protobuf message objdiff.diff.FunctionDiff + * @generated from protobuf message objdiff.diff.SymbolRef */ -export interface FunctionDiff { +export interface SymbolRef { + /** + * @generated from protobuf field: optional uint32 section_index = 1; + */ + section_index?: number; + /** + * @generated from protobuf field: uint32 symbol_index = 2; + */ + symbol_index: number; +} +/** + * @generated from protobuf message objdiff.diff.SymbolDiff + */ +export interface SymbolDiff { /** * @generated from protobuf field: objdiff.diff.Symbol symbol = 1; */ @@ -311,6 +324,12 @@ export interface FunctionDiff { * @generated from protobuf field: optional float match_percent = 3; */ match_percent?: number; + /** + * The symbol ref in the _other_ object that this symbol was diffed against + * + * @generated from protobuf field: optional objdiff.diff.SymbolRef target = 5; + */ + target?: SymbolRef; } /** * @generated from protobuf message objdiff.diff.DataDiff @@ -352,9 +371,9 @@ export interface SectionDiff { */ address: bigint; /** - * @generated from protobuf field: repeated objdiff.diff.FunctionDiff functions = 5; + * @generated from protobuf field: repeated objdiff.diff.SymbolDiff symbols = 5; */ - functions: FunctionDiff[]; + symbols: SymbolDiff[]; /** * @generated from protobuf field: repeated objdiff.diff.DataDiff data = 6; */ @@ -405,17 +424,17 @@ export enum SymbolFlag { */ SYMBOL_LOCAL = 2, /** - * @generated from protobuf enum value: SYMBOL_WEAK = 3; + * @generated from protobuf enum value: SYMBOL_WEAK = 4; */ - SYMBOL_WEAK = 3, + SYMBOL_WEAK = 4, /** - * @generated from protobuf enum value: SYMBOL_COMMON = 4; + * @generated from protobuf enum value: SYMBOL_COMMON = 8; */ - SYMBOL_COMMON = 4, + SYMBOL_COMMON = 8, /** - * @generated from protobuf enum value: SYMBOL_HIDDEN = 5; + * @generated from protobuf enum value: SYMBOL_HIDDEN = 16; */ - SYMBOL_HIDDEN = 5 + SYMBOL_HIDDEN = 16 } /** * @generated from protobuf enum objdiff.diff.DiffKind @@ -1196,22 +1215,77 @@ class InstructionBranchTo$Type extends MessageType { */ export const InstructionBranchTo = new InstructionBranchTo$Type(); // @generated message type with reflection information, may provide speed optimized methods -class FunctionDiff$Type extends MessageType { +class SymbolRef$Type extends MessageType { constructor() { - super("objdiff.diff.FunctionDiff", [ - { no: 1, name: "symbol", kind: "message", T: () => Symbol }, - { no: 2, name: "instructions", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => InstructionDiff }, - { no: 3, name: "match_percent", kind: "scalar", localName: "match_percent", opt: true, T: 2 /*ScalarType.FLOAT*/ } + super("objdiff.diff.SymbolRef", [ + { no: 1, name: "section_index", kind: "scalar", localName: "section_index", opt: true, T: 13 /*ScalarType.UINT32*/ }, + { no: 2, name: "symbol_index", kind: "scalar", localName: "symbol_index", T: 13 /*ScalarType.UINT32*/ } ]); } - create(value?: PartialMessage): FunctionDiff { + create(value?: PartialMessage): SymbolRef { + const message = globalThis.Object.create((this.messagePrototype!)); + message.symbol_index = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SymbolRef): SymbolRef { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional uint32 section_index */ 1: + message.section_index = reader.uint32(); + break; + case /* uint32 symbol_index */ 2: + message.symbol_index = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: SymbolRef, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional uint32 section_index = 1; */ + if (message.section_index !== undefined) + writer.tag(1, WireType.Varint).uint32(message.section_index); + /* uint32 symbol_index = 2; */ + if (message.symbol_index !== 0) + writer.tag(2, WireType.Varint).uint32(message.symbol_index); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message objdiff.diff.SymbolRef + */ +export const SymbolRef = new SymbolRef$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class SymbolDiff$Type extends MessageType { + constructor() { + super("objdiff.diff.SymbolDiff", [ + { no: 1, name: "symbol", kind: "message", T: () => Symbol }, + { no: 2, name: "instructions", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => InstructionDiff }, + { no: 3, name: "match_percent", kind: "scalar", localName: "match_percent", opt: true, T: 2 /*ScalarType.FLOAT*/ }, + { no: 5, name: "target", kind: "message", T: () => SymbolRef } + ]); + } + create(value?: PartialMessage): SymbolDiff { const message = globalThis.Object.create((this.messagePrototype!)); message.instructions = []; if (value !== undefined) - reflectionMergePartial(this, message, value); + reflectionMergePartial(this, message, value); return message; } - internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FunctionDiff): FunctionDiff { + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SymbolDiff): SymbolDiff { let message = target ?? this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); @@ -1225,6 +1299,9 @@ class FunctionDiff$Type extends MessageType { case /* optional float match_percent */ 3: message.match_percent = reader.float(); break; + case /* optional objdiff.diff.SymbolRef target */ 5: + message.target = SymbolRef.internalBinaryRead(reader, reader.uint32(), options, message.target); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -1236,7 +1313,7 @@ class FunctionDiff$Type extends MessageType { } return message; } - internalBinaryWrite(message: FunctionDiff, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + internalBinaryWrite(message: SymbolDiff, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { /* objdiff.diff.Symbol symbol = 1; */ if (message.symbol) Symbol.internalBinaryWrite(message.symbol, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); @@ -1246,6 +1323,9 @@ class FunctionDiff$Type extends MessageType { /* optional float match_percent = 3; */ if (message.match_percent !== undefined) writer.tag(3, WireType.Bit32).float(message.match_percent); + /* optional objdiff.diff.SymbolRef target = 5; */ + if (message.target) + SymbolRef.internalBinaryWrite(message.target, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -1253,9 +1333,9 @@ class FunctionDiff$Type extends MessageType { } } /** - * @generated MessageType for protobuf message objdiff.diff.FunctionDiff + * @generated MessageType for protobuf message objdiff.diff.SymbolDiff */ -export const FunctionDiff = new FunctionDiff$Type(); +export const SymbolDiff = new SymbolDiff$Type(); // @generated message type with reflection information, may provide speed optimized methods class DataDiff$Type extends MessageType { constructor() { @@ -1327,7 +1407,7 @@ class SectionDiff$Type extends MessageType { { no: 2, name: "kind", kind: "enum", T: () => ["objdiff.diff.SectionKind", SectionKind] }, { no: 3, name: "size", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, { no: 4, name: "address", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, - { no: 5, name: "functions", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => FunctionDiff }, + { no: 5, name: "symbols", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => SymbolDiff }, { no: 6, name: "data", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => DataDiff }, { no: 7, name: "match_percent", kind: "scalar", localName: "match_percent", opt: true, T: 2 /*ScalarType.FLOAT*/ } ]); @@ -1338,7 +1418,7 @@ class SectionDiff$Type extends MessageType { message.kind = 0; message.size = 0n; message.address = 0n; - message.functions = []; + message.symbols = []; message.data = []; if (value !== undefined) reflectionMergePartial(this, message, value); @@ -1361,8 +1441,8 @@ class SectionDiff$Type extends MessageType { case /* uint64 address */ 4: message.address = reader.uint64().toBigInt(); break; - case /* repeated objdiff.diff.FunctionDiff functions */ 5: - message.functions.push(FunctionDiff.internalBinaryRead(reader, reader.uint32(), options)); + case /* repeated objdiff.diff.SymbolDiff symbols */ 5: + message.symbols.push(SymbolDiff.internalBinaryRead(reader, reader.uint32(), options)); break; case /* repeated objdiff.diff.DataDiff data */ 6: message.data.push(DataDiff.internalBinaryRead(reader, reader.uint32(), options)); @@ -1394,9 +1474,9 @@ class SectionDiff$Type extends MessageType { /* uint64 address = 4; */ if (message.address !== 0n) writer.tag(4, WireType.Varint).uint64(message.address); - /* repeated objdiff.diff.FunctionDiff functions = 5; */ - for (let i = 0; i < message.functions.length; i++) - FunctionDiff.internalBinaryWrite(message.functions[i], writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + /* repeated objdiff.diff.SymbolDiff symbols = 5; */ + for (let i = 0; i < message.symbols.length; i++) + SymbolDiff.internalBinaryWrite(message.symbols[i], writer.tag(5, WireType.LengthDelimited).fork(), options).join(); /* repeated objdiff.diff.DataDiff data = 6; */ for (let i = 0; i < message.data.length; i++) DataDiff.internalBinaryWrite(message.data[i], writer.tag(6, WireType.LengthDelimited).fork(), options).join(); diff --git a/shared/messages.ts b/shared/messages.ts new file mode 100644 index 0000000..8e36a1c --- /dev/null +++ b/shared/messages.ts @@ -0,0 +1,36 @@ +export type DiffMessage = { + type: 'diff'; + data: ArrayBuffer; +}; + +export type TaskMessage = { + type: 'task'; + taskType: string; + running: boolean; +}; + +export type StateMessage = { + type: 'state'; + configLoaded: boolean; + currentFile: string | null; +}; + +// extension -> webview +export type InboundMessage = DiffMessage | TaskMessage | StateMessage; + +export type ReadyMessage = { + type: 'ready'; +}; + +export type LineRangesMessage = { + type: 'lineRanges'; + data: Array<{ start: number; end: number }>; +}; + +export type RunTaskMessage = { + type: 'runTask'; + taskType: string; +}; + +// webview -> extension +export type OutboundMessage = ReadyMessage | LineRangesMessage | RunTaskMessage; diff --git a/src/extension.ts b/src/extension.ts index ff5f450..d3d4405 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,5 +1,6 @@ import * as picomatch from 'picomatch'; import * as vscode from 'vscode'; +import type { InboundMessage, OutboundMessage } from '../shared/messages'; import { DEFAULT_WATCH_PATTERNS, type ObjdiffConfiguration } from './config'; const CONFIG_FILENAME = 'objdiff.json'; @@ -7,13 +8,21 @@ const CONFIG_FILENAME = 'objdiff.json'; export class ObjdiffWorkspace extends vscode.Disposable { public config?: ObjdiffConfiguration; public configWatcher: vscode.FileSystemWatcher; + public currentFile?: string; public workspaceWatcher?: vscode.FileSystemWatcher; + public onDidChangeConfig: vscode.Event; + public onDidChangeCurrentFile: vscode.Event; private subscriptions: vscode.Disposable[] = []; private wwSubscriptions: vscode.Disposable[] = []; - private currentDiff?: vscode.Uri; // private currentTask?: () => void; private pathMatcher?: picomatch.Matcher; + private didChangeConfigEmitter = new vscode.EventEmitter< + ObjdiffConfiguration | undefined + >(); + private didChangeCurrentFileEmitter = new vscode.EventEmitter< + string | undefined + >(); constructor( public readonly chan: vscode.LogOutputChannel, @@ -23,6 +32,9 @@ export class ObjdiffWorkspace extends vscode.Disposable { super(() => { this.disposeImpl(); }); + this.onDidChangeConfig = this.didChangeConfigEmitter.event; + this.onDidChangeCurrentFile = this.didChangeCurrentFileEmitter.event; + this.configWatcher = vscode.workspace.createFileSystemWatcher( new vscode.RelativePattern(workspaceFolder, CONFIG_FILENAME), ); @@ -139,6 +151,7 @@ export class ObjdiffWorkspace extends vscode.Disposable { this.wwSubscriptions, ); } + this.didChangeConfigEmitter.fire(this.config); this.tryDiff(); } @@ -156,25 +169,22 @@ export class ObjdiffWorkspace extends vscode.Disposable { this.tryDiff(); } - tryDiff() { + private tryUpdateActiveFile() { 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 activeEditor = vscode.window.activeTextEditor; + if (!activeEditor) { + this.chan.warn('No active editor'); + return; } - const fsPath = this.currentDiff.fsPath; + if (activeEditor.document.uri.scheme !== 'file') { + this.chan.warn('Active editor not a file'); + return; + } + const fsPath = activeEditor.document.uri.fsPath; if (!fsPath.startsWith(this.workspaceFolder.uri.fsPath)) { - this.chan.warn('Active editor not in workspace'); + this.chan.warn('Active editor not in workspace', fsPath); return; } const relPath = fsPath.slice(this.workspaceFolder.uri.fsPath.length + 1); @@ -182,7 +192,27 @@ export class ObjdiffWorkspace extends vscode.Disposable { (obj) => obj.metadata?.source_path === relPath, ); if (!obj) { - this.chan.warn('No object found for', relPath); + this.chan.warn('No object found for', this.currentFile); + return; + } + this.currentFile = relPath; + this.didChangeCurrentFileEmitter.fire(this.currentFile); + } + + tryDiff() { + if (!this.config) { + return; + } + this.tryUpdateActiveFile(); + if (!this.currentFile) { + this.chan.warn('No active file'); + return; + } + const obj = (this.config.units || this.config.objects)?.find( + (obj) => obj.metadata?.source_path === this.currentFile, + ); + if (!obj) { + this.chan.warn('No object found for', this.currentFile); return; } const targetPath = @@ -252,6 +282,7 @@ export class ObjdiffWorkspace extends vscode.Disposable { const task = new vscode.Task( { type: 'objdiff', + taskType: 'build', startTime, }, this.workspaceFolder, @@ -312,6 +343,11 @@ export function activate(context: vscode.ExtensionContext) { // const storageDir = storageUri.fsPath; // chan.info('Storage directory: ' + storageDir); + const webviews: { + webview: vscode.Webview; + subscriptions: vscode.Disposable[]; + }[] = []; + let workspace: ObjdiffWorkspace | undefined; if (vscode.workspace.workspaceFolders?.[0]) { workspace = new ObjdiffWorkspace( @@ -319,18 +355,63 @@ export function activate(context: vscode.ExtensionContext) { vscode.workspace.workspaceFolders[0], storageUri, ); + workspace.onDidChangeConfig( + (config) => { + for (const view of webviews) { + view.webview.postMessage({ + type: 'state', + configLoaded: !!config, + currentFile: workspace?.currentFile || null, + } as InboundMessage); + } + }, + undefined, + context.subscriptions, + ); + workspace.onDidChangeCurrentFile( + (currentFile) => { + for (const view of webviews) { + view.webview.postMessage({ + type: 'state', + configLoaded: !!workspace?.config, + currentFile, + } as InboundMessage); + } + }, + undefined, + context.subscriptions, + ); context.subscriptions.push(workspace); } + chan.info('Workspace folders', vscode.workspace.workspaceFolders); + vscode.workspace.onDidChangeWorkspaceFolders( + (e) => { + chan.info('Workspace folders changed', e); + }, + undefined, + context.subscriptions, + ); context.subscriptions.push( vscode.commands.registerCommand('objdiff.build', () => { - if (workspace) { - workspace.tryDiff(); - } + workspace?.tryDiff(); }), ); - - const webviews: vscode.Webview[] = []; + context.subscriptions.push( + vscode.commands.registerCommand('objdiff.copySymbolName', (opts) => { + chan.info('Copy command', opts); + vscode.env.clipboard.writeText(opts.symbolName); + }), + ); + context.subscriptions.push( + vscode.commands.registerCommand( + 'objdiff.copySymbolDemangledName', + (opts) => { + chan.info('Copy demangled command', opts); + vscode.env.clipboard.writeText(opts.symbolDemangledName); + }, + ), + ); const backgroundColors = [ 'rgba(255, 0, 255, 0.3)', @@ -350,8 +431,42 @@ export function activate(context: vscode.ExtensionContext) { }); }); - context.subscriptions.push( - vscode.tasks.onDidEndTaskProcess(async (e) => { + vscode.tasks.onDidStartTask( + (e) => { + if (e.execution.task.definition.type !== 'objdiff') { + return; + } + for (const view of webviews) { + view.webview.postMessage({ + type: 'task', + taskType: e.execution.task.definition.taskType, + running: true, + } as InboundMessage); + } + }, + undefined, + context.subscriptions, + ); + vscode.tasks.onDidEndTask( + (e) => { + if (e.execution.task.definition.type !== 'objdiff') { + return; + } + for (const view of webviews) { + view.webview.postMessage({ + type: 'task', + taskType: e.execution.task.definition.taskType, + running: false, + } as InboundMessage); + } + }, + undefined, + context.subscriptions, + ); + + let cachedData: Uint8Array | null = null; + vscode.tasks.onDidEndTaskProcess( + async (e) => { if (e.execution.task.definition.type !== 'objdiff') { return; } @@ -373,18 +488,15 @@ export function activate(context: vscode.ExtensionContext) { '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({ + for (const view of webviews) { + view.webview.postMessage({ type: 'diff', data: data.buffer, - }); + } as InboundMessage); } + cachedData = data; } catch (reason) { - chan.error('Failed to read output file', reason); + workspace?.showError('Failed to read output file', reason); } } else { workspace?.showError(`Build failed with code ${e.exitCode}`); @@ -392,10 +504,12 @@ export function activate(context: vscode.ExtensionContext) { vscode.workspace.fs.delete(outputUri).then( () => {}, (reason) => { - chan.error('Failed to delete output file', reason); + workspace?.showError('Failed to delete output file', reason); }, ); - }), + }, + undefined, + context.subscriptions, ); const textDecoder = new TextDecoder(); @@ -423,10 +537,24 @@ export function activate(context: vscode.ExtensionContext) { enableScripts: true, }; view.webview.html = html; - context.subscriptions.push( - view.webview.onDidReceiveMessage((message) => { + const subscriptions: vscode.Disposable[] = []; + view.webview.onDidReceiveMessage( + (untypedMessage) => { + const message = untypedMessage as OutboundMessage; if (message.type === 'ready') { chan.info('Webview ready'); + view.webview.postMessage({ + type: 'state', + configLoaded: !!workspace?.config, + currentFile: workspace?.currentFile || null, + } as InboundMessage); + if (cachedData) { + chan.info('Sending cached diff to webview'); + view.webview.postMessage({ + type: 'diff', + data: cachedData.buffer, + } as InboundMessage); + } } else if (message.type === 'lineRanges') { for (const editor of vscode.window.visibleTextEditors) { if (editor.document.uri.scheme !== 'file') { @@ -444,18 +572,38 @@ export function activate(context: vscode.ExtensionContext) { idx = (idx + 1) % decorationTypes.length; } } + } else if (message.type === 'runTask') { + if (message.taskType === 'build') { + workspace?.tryDiff(); + } else { + chan.warn('Unknown task type', message.taskType); + } + } else { + chan.warn('Unknown message', message); } - }), + }, + undefined, + subscriptions, ); - context.subscriptions.push( - view.onDidDispose(() => { - const idx = webviews.indexOf(view.webview); - if (idx >= 0) { - webviews.splice(idx, 1); + view.onDidDispose( + () => { + for (const sub of subscriptions) { + sub.dispose(); } - }), + for (let i = 0; i < webviews.length; i++) { + if (webviews[i].webview === view.webview) { + webviews.splice(i, 1); + break; + } + } + }, + undefined, + context.subscriptions, ); - webviews.push(view.webview); + webviews.push({ + webview: view.webview, + subscriptions, + }); }, }), ); diff --git a/tsconfig.json b/tsconfig.json index 8dc063e..4373529 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,5 +19,5 @@ "noUnusedLocals": true, "noUnusedParameters": true }, - "include": ["src", "webview", "gen"] + "include": ["src", "webview", "shared"] } diff --git a/webview/App.css b/webview/App.css index e5884f8..5150a4d 100644 --- a/webview/App.css +++ b/webview/App.css @@ -1,28 +1,32 @@ :root { --font-size: var(--vscode-editor-font-size, 13px); --list-row-height: calc(var(--font-size) * 1.33); + color-scheme: light dark; } body { margin: 0; + padding: 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 - ); + color: var(--vscode-foreground, #fff); + font-family: var(--vscode-font-family, system-ui); + font-weight: var(--vscode-font-weight, normal); + font-size: var(--vscode-font-size, 13px); background-color: var(--vscode-editor-background, #1e1e1e); + + &.vscode-light, + &.vscode-high-contrast-light { + color-scheme: light; + } + &.vscode-dark, + &.vscode-high-contrast-dark { + color-scheme: dark; + } } #root { display: flex; + flex-flow: column; min-height: 100vh; } @@ -34,15 +38,48 @@ body { text-align: center; flex-direction: column; justify-content: center; + + h1 { + font-size: 3.6rem; + font-weight: 700; + } + + p { + font-size: 1.2rem; + font-weight: 400; + opacity: 0.5; + } } -.content h1 { - font-size: 3.6rem; - font-weight: 700; -} +button { + background-color: var(--vscode-button-secondaryBackground); + color: var(--vscode-button-secondaryForeground); + border: 1px solid var(--vscode-button-border); + border-radius: 3px; + cursor: pointer; -.content p { - font-size: 1.2rem; - font-weight: 400; - opacity: 0.5; + font-family: var(--vscode-font-family, system-ui); + font-weight: var(--vscode-font-weight, normal); + font-size: var(--vscode-font-size, 13px); + + &:hover { + background-color: var(--vscode-button-secondaryHoverBackground); + } + + &:focus { + opacity: 1; + outline-color: var(--vscode-focusBorder); + outline-offset: -1px; + outline-style: solid; + outline-width: 1px; + } + + &:active { + outline: 0 !important; + background-color: var(--vscode-toolbar-activeBackground); + } + + &:disabled { + color: var(--vscode-disabledForeground); + } } diff --git a/webview/App.tsx b/webview/App.tsx index e9f2067..5b1bae6 100644 --- a/webview/App.tsx +++ b/webview/App.tsx @@ -1,30 +1,30 @@ import './App.css'; -import { SectionKind } from '../gen/diff_pb'; +import { SectionKind } from '../shared/gen/diff_pb'; import type { Symbol as DiffSymbol, - FunctionDiff, ObjectDiff, -} from '../gen/diff_pb'; + SymbolDiff, +} from '../shared/gen/diff_pb'; import FunctionView from './FunctionView'; import SymbolsView from './SymbolsView'; -import { useAppStore, useDiffStore } from './state'; +import { useAppStore, useExtensionStore, vscode } from './state'; import type { SymbolRefByName } from './state'; const findSymbol = ( obj: ObjectDiff | undefined, symbolRef: SymbolRefByName | null, -): FunctionDiff | null => { +): SymbolDiff | 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; + for (const diff of section.symbols) { + const symbol = diff.symbol as DiffSymbol; if (symbol.name === symbolRef.symbol_name) { - return fn; + return diff; } } } @@ -34,23 +34,39 @@ const findSymbol = ( }; const App = () => { - const { diff } = useDiffStore(); + const { diff } = useExtensionStore(); const selectedSymbolRef = useAppStore((state) => state.selectedSymbol); + const buildRunning = useExtensionStore((state) => state.buildRunning); + const configLoaded = useExtensionStore((state) => state.configLoaded); 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 ; } - return ; + return ; } return (

objdiff

-

Coming soon to a VS Code near you.

+ {configLoaded ? ( +

+ Open a source file and{' '} + + . +

+ ) : ( +

No configuration loaded.

+ )}
); }; diff --git a/webview/FunctionView.module.css b/webview/FunctionView.module.css index cfb4553..7ebb794 100644 --- a/webview/FunctionView.module.css +++ b/webview/FunctionView.module.css @@ -1,4 +1,5 @@ .instruction-list { + flex: 1 1 auto; } .instruction-row { @@ -16,87 +17,91 @@ text-wrap: nowrap; white-space: pre; overflow: hidden; + padding-left: 0.5em; } .highlightable { cursor: pointer; } - -.diff_change { - color: #6d6dff; -} -.rotation0 { - color: magenta; -} -.rotation1 { - color: cyan; -} -.rotation2 { - color: rgb(0, 212, 0); -} -.rotation3 { - color: red; -} -.rotation4 { - color: rgb(103, 106, 255); -} -.rotation5 { - color: lightpink; -} -.rotation6 { - color: lightcyan; -} -.rotation7 { - color: lightgreen; -} -.rotation8 { - color: grey; -} -.symbol { - color: white; -} .line-number { color: var(--vscode-editorLineNumber-foreground); } +.diff_any { + background-color: rgba(255, 255, 255, 0.02); +} +.diff_change { + color: #6d6dff; +} +.diff_add { + color: #45bd00; +} +.diff_remove { + color: #c82829; +} +.symbol { + color: light-dark(black, white); +} -:global(body.vscode-light) { - .rotation0 { +.rotation0 { + color: light-dark( /* hsv(0° 60% 80%) */ - color: rgb(205, 82, 82); - } - .rotation1 { + rgb(205, 82, 82), + magenta + ); +} +.rotation1 { + color: light-dark( /* hsv(40° 60% 80%) */ - color: rgb(205, 164, 82); - } - .rotation2 { + rgb(205, 164, 82), + cyan + ); +} +.rotation2 { + color: light-dark( /* hsv(80° 60% 80%) */ - color: rgb(164, 205, 82); - } - .rotation3 { + rgb(164, 205, 82), + rgb(0, 212, 0) + ); +} +.rotation3 { + color: light-dark( /* hsv(120° 60% 80%) */ - color: rgb(82, 205, 82); - } - .rotation4 { + rgb(82, 205, 82), + red + ); +} +.rotation4 { + color: light-dark( /* hsv(160° 60% 80%) */ - color: rgb(82, 205, 164); - } - .rotation5 { + rgb(82, 205, 164), + rgb(103, 106, 255) + ); +} +.rotation5 { + color: light-dark( /* hsv(200° 60% 80%) */ - color: rgb(82, 164, 205); - } - .rotation6 { + rgb(82, 164, 205), + lightpink + ); +} +.rotation6 { + color: light-dark( /* hsv(240° 60% 80%) */ - color: rgb(82, 82, 205); - } - .rotation7 { + rgb(82, 82, 205), + lightcyan + ); +} +.rotation7 { + color: light-dark( /* hsv(280° 60% 80%) */ - color: rgb(164, 82, 205); - } - .rotation8 { + rgb(164, 82, 205), + lightgreen + ); +} +.rotation8 { + color: light-dark( /* hsv(320° 60% 80%) */ - color: rgb(205, 82, 164); - } - .symbol { - color: black; - } + rgb(205, 82, 164), + grey + ); } diff --git a/webview/FunctionView.tsx b/webview/FunctionView.tsx index a9d4ad2..31bb090 100644 --- a/webview/FunctionView.tsx +++ b/webview/FunctionView.tsx @@ -1,18 +1,20 @@ import styles from './FunctionView.module.css'; +import headerStyles from './Header.module.css'; import clsx from 'clsx'; import memoize from 'memoize-one'; -import { memo } from 'react'; +import { memo, useMemo } from 'react'; import AutoSizer from 'react-virtualized-auto-sizer'; import { FixedSizeList, areEqual } from 'react-window'; import type { ListChildComponentProps } from 'react-window'; -import { DiffKind } from '../gen/diff_pb'; +import { DiffKind } from '../shared/gen/diff_pb'; import type { Symbol as DiffSymbol, - FunctionDiff, InstructionDiff, -} from '../gen/diff_pb'; + SymbolDiff, +} from '../shared/gen/diff_pb'; import { displayDiff } from './diff'; +import { useAppStore } from './state'; import { useFontSize } from './util'; const AsmCell = ({ @@ -132,13 +134,30 @@ const AsmCell = ({ index++; } }); - return
{out}
; + + const classes = [styles.instructionCell]; + if (insDiff.diff_kind) { + classes.push(styles.diff_any); + } + switch (insDiff.diff_kind) { + case DiffKind.DIFF_DELETE: + classes.push(styles.diff_remove); + break; + case DiffKind.DIFF_INSERT: + classes.push(styles.diff_add); + break; + case DiffKind.DIFF_REPLACE: + classes.push(styles.diff_change); + break; + } + + return
{out}
; }; type ItemData = { itemCount: number; - left: FunctionDiff | null; - right: FunctionDiff | null; + left: SymbolDiff | null; + right: SymbolDiff | null; }; const AsmRow = memo( @@ -160,7 +179,7 @@ const AsmRow = memo( ); const createItemData = memoize( - (left: FunctionDiff | null, right: FunctionDiff | null) => { + (left: SymbolDiff | null, right: SymbolDiff | null) => { const itemCount = Math.max( left?.instructions.length || 0, right?.instructions.length || 0, @@ -172,25 +191,49 @@ const createItemData = memoize( const FunctionView = ({ left, right, -}: { left: FunctionDiff | null; right: FunctionDiff | null }) => { +}: { left: SymbolDiff | null; right: SymbolDiff | null }) => { + const setSelectedSymbol = useAppStore((state) => state.setSelectedSymbol); + const setSymbolScrollOffset = useAppStore( + (state) => state.setSymbolScrollOffset, + ); + + const symbolName = left?.symbol?.name || right?.symbol?.name || ''; + const initialScrollOffset = useMemo( + () => useAppStore.getState().symbolScrollOffsets[symbolName] || 0, + [symbolName], + ); + const itemSize = useFontSize() * 1.33; const itemData = createItemData(left, right); + const demangledName = + left?.symbol?.demangled_name || right?.symbol?.demangled_name; return ( - - {({ height, width }) => ( - - {AsmRow} - - )} - + <> +
+ + {demangledName} +
+
+ + {({ height, width }) => ( + { + setSymbolScrollOffset(symbolName, e.scrollOffset); + }} + initialScrollOffset={initialScrollOffset} + > + {AsmRow} + + )} + +
+ ); }; diff --git a/webview/Header.module.css b/webview/Header.module.css new file mode 100644 index 0000000..8bad214 --- /dev/null +++ b/webview/Header.module.css @@ -0,0 +1,19 @@ +.header { + display: flex; + flex-direction: row; + align-items: center; + gap: 0.5em; + padding: 0.5em; + background-color: var(--vscode-panel-background); + border-bottom: 1px solid var(--vscode-menu-separatorBackground); + + > span { + font-family: var(--vscode-editor-font-family, monospace); + font-weight: var(--vscode-editor-font-weight, normal); + font-size: var(--font-size); + text-wrap: nowrap; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + } +} diff --git a/webview/SymbolsView.module.css b/webview/SymbolsView.module.css index 3f5e00a..593b256 100644 --- a/webview/SymbolsView.module.css +++ b/webview/SymbolsView.module.css @@ -1,4 +1,14 @@ +.symbols { + flex: 1 1 0; + display: flex; + flex-flow: row; + overflow: auto; + gap: 0.5em; +} + .symbol-list { + flex: 1 1 0; + overflow-x: scroll; list-style-type: none; margin: 0; padding: 0; @@ -6,7 +16,13 @@ li { cursor: pointer; user-select: none; - /* margin: 0 0.5rem; */ + height: var(--list-row-height); + + font-family: var(--vscode-editor-font-family, monospace); + font-weight: var(--vscode-editor-font-weight, normal); + font-size: var(--font-size); + text-wrap: nowrap; + white-space: pre; &:hover { background-color: var(--vscode-list-hoverBackground); @@ -15,9 +31,31 @@ } .section { - padding-left: 0; + padding-left: 0.5em; } .symbol { - padding-left: 0.5rem; + padding-left: 2em; +} + +.flag-global { + color: lightgreen; +} + +.flag-weak { + /* todo */ +} + +.symbol-name { + color: light-dark(black, white); +} + +.percent-100 { + color: lightgreen; +} +.percent-50 { + color: lightblue; +} +.percent-0 { + color: lightcoral; } diff --git a/webview/SymbolsView.tsx b/webview/SymbolsView.tsx index d5eb2dd..e899d47 100644 --- a/webview/SymbolsView.tsx +++ b/webview/SymbolsView.tsx @@ -1,42 +1,147 @@ +import headerStyles from './Header.module.css'; import styles from './SymbolsView.module.css'; -import { SectionKind } from '../gen/diff_pb'; -import type { Symbol as DiffSymbol, ObjectDiff } from '../gen/diff_pb'; -import { useAppStore } from './state'; +import { + type DiffResult, + type Symbol as DiffSymbol, + type ObjectDiff, + SymbolFlag, +} from '../shared/gen/diff_pb'; +import { useAppStore, useExtensionStore, vscode } from './state'; -const SymbolsView = ({ obj }: { obj: ObjectDiff }) => { +const SymbolsList = ({ obj }: { obj: ObjectDiff }) => { const setSelectedSymbol = useAppStore((state) => state.setSelectedSymbol); - const items = []; + let sectionIndex = 0; for (const section of obj.sections) { + const sectionKey = `section-${sectionIndex++}`; + let percentElem = null; + if (section.match_percent != null) { + let className = styles.percent0; + if (section.match_percent === 100) { + className = styles.percent100; + } else if (section.match_percent >= 50) { + className = styles.percent50; + } + percentElem = ( + <> + {' ('} + + {Math.floor(section.match_percent).toFixed(0)}% + + {')'} + + ); + } items.push( -
  • - {section.name} +
  • + {section.name} ({section.size.toString(16)}){percentElem}
  • , ); - if (section.kind === SectionKind.SECTION_TEXT) { - for (const fn of section.functions) { - const symbol = fn.symbol as DiffSymbol; - items.push( -
  • { - setSelectedSymbol({ - symbol_name: symbol.name, - section_name: section.name, - }); - }} - > - {symbol.name} -
  • , + for (const diff of section.symbols) { + const symbol = diff.symbol as DiffSymbol; + const flags = []; + if (symbol.flags & SymbolFlag.SYMBOL_GLOBAL) { + flags.push( + + g + , ); } - } else { - // TODO + if (symbol.flags & SymbolFlag.SYMBOL_WEAK) { + flags.push( + + w + , + ); + } + if (symbol.flags & SymbolFlag.SYMBOL_LOCAL) { + flags.push( + + l + , + ); + } + if (symbol.flags & SymbolFlag.SYMBOL_COMMON) { + flags.push( + + c + , + ); + } + let flagsElem = null; + if (flags.length > 0) { + flagsElem = <>[{flags}] ; + } + let percentElem = null; + if (diff.match_percent != null) { + let className = styles.percent0; + if (diff.match_percent === 100) { + className = styles.percent100; + } else if (diff.match_percent >= 50) { + className = styles.percent50; + } + percentElem = ( + <> + {'('} + + {Math.floor(diff.match_percent).toFixed(0)}% + + {') '} + + ); + } + items.push( +
  • { + setSelectedSymbol({ + symbol_name: symbol.name, + section_name: section.name, + }); + }} + data-vscode-context={JSON.stringify({ + contextType: 'symbol', + preventDefaultContextMenuItems: true, + symbolName: symbol.name, + symbolDemangledName: symbol.demangled_name, + })} + > + {flagsElem} + {percentElem} + + {symbol.demangled_name || symbol.name} + +
  • , + ); } } return
      {items}
    ; }; +const SymbolsView = ({ diff }: { diff: DiffResult }) => { + const buildRunning = useExtensionStore((state) => state.buildRunning); + const currentFile = useExtensionStore((state) => state.currentFile); + return ( + <> +
    + + {buildRunning ? Building... : {currentFile}} +
    +
    + {diff.left && } + {diff.right && } +
    + + ); +}; + export default SymbolsView; diff --git a/webview/diff.ts b/webview/diff.ts index a480541..650dcf4 100644 --- a/webview/diff.ts +++ b/webview/diff.ts @@ -2,7 +2,7 @@ import type { ArgumentValue, InstructionDiff, RelocationTarget, -} from '../gen/diff_pb'; +} from '../shared/gen/diff_pb'; export type DiffText = | DiffTextBasic diff --git a/webview/state.ts b/webview/state.ts index eb239aa..1943392 100644 --- a/webview/state.ts +++ b/webview/state.ts @@ -1,6 +1,6 @@ -import type { WebviewApi } from 'vscode-webview'; import { create } from 'zustand'; -import { DiffKind, DiffResult } from '../gen/diff_pb'; +import { DiffResult } from '../shared/gen/diff_pb'; +import type { InboundMessage, OutboundMessage } from '../shared/messages'; export type SymbolRefByName = { symbol_name: string; @@ -9,23 +9,48 @@ export type SymbolRefByName = { export interface AppState { selectedSymbol: SymbolRefByName | null; + symbolScrollOffsets: Record; setSelectedSymbol: (selectedSymbol: SymbolRefByName | null) => void; + setSymbolScrollOffset: (symbolName: string, offset: number) => void; } export const useAppStore = create((set) => ({ selectedSymbol: null, + symbolScrollOffsets: {}, setSelectedSymbol: (selectedSymbol) => set({ selectedSymbol }), + setSymbolScrollOffset: (symbolName, offset) => + set((state) => ({ + symbolScrollOffsets: { + ...state.symbolScrollOffsets, + [symbolName]: offset, + }, + })), })); -export type DiffState = { - diff?: DiffResult; +export type ExtensionState = { + diff: DiffResult | null; + buildRunning: boolean; + configLoaded: boolean; + currentFile: string | null; }; -export const useDiffStore = create(() => ({})); +export const useExtensionStore = create(() => ({ + diff: null, + buildRunning: false, + configLoaded: false, + currentFile: null, +})); -let vscode: WebviewApi; +// Copy of vscode.WebviewApi with concrete message types +export interface MyWebviewApi { + postMessage(message: OutboundMessage): void; + getState(): StateType | undefined; + setState(newState: T): T; +} + +let vscode: MyWebviewApi; if (typeof acquireVsCodeApi === 'function') { - vscode = acquireVsCodeApi(); + vscode = acquireVsCodeApi(); } else { - let state: DiffState | undefined; + let state: AppState | undefined; vscode = { postMessage: () => {}, getState: () => state, @@ -35,48 +60,77 @@ if (typeof acquireVsCodeApi === 'function') { }, }; } +const storedState = vscode.getState(); +if (storedState) { + useAppStore.setState(storedState); +} +let timeoutId: ReturnType | undefined; +useAppStore.subscribe((state) => { + // Debounce state updates + if (timeoutId) { + clearTimeout(timeoutId); + } + timeoutId = setTimeout(() => { + vscode.setState(state); + timeoutId = undefined; + }, 100); +}); vscode.postMessage({ type: 'ready' }); +export { vscode }; window.addEventListener('message', (event) => { - const message = event.data; - if (message && typeof message === 'object') { - console.log('Received message', message); - if (message.type === 'diff') { - const diff = DiffResult.fromBinary(new Uint8Array(message.data)); + const message = event.data as InboundMessage; + if (message.type === 'diff') { + const start = performance.now(); + const diff = DiffResult.fromBinary(new Uint8Array(message.data)); + const end = performance.now(); + console.debug('Diff deserialization time:', end - start, 'ms'); - const lineRanges = []; - for (const section of diff.right?.sections || []) { - for (const fn of section.functions) { - let currentRange: { start: number; end: number } | null = null; - for (const ins of fn.instructions) { - let lineNumber = ins.instruction?.line_number; - if (lineNumber == null) { - continue; - } - lineNumber = lineNumber - 1; - if (ins.diff_kind !== DiffKind.DIFF_NONE) { - if (currentRange !== null) { - currentRange.end = lineNumber; - } else { - currentRange = { - start: lineNumber, - end: lineNumber, - }; - } - } else if (currentRange !== null && lineNumber > currentRange.end) { - lineRanges.push(currentRange); - currentRange = null; - } - } - if (currentRange !== null) { - lineRanges.push(currentRange); - } - } - } - console.log('lineRanges', lineRanges); - vscode.postMessage({ type: 'lineRanges', data: lineRanges }); + // const lineRanges = []; + // for (const section of diff.right?.sections || []) { + // for (const diff of section.symbols) { + // let currentRange: { start: number; end: number } | null = null; + // for (const ins of diff.instructions) { + // let lineNumber = ins.instruction?.line_number; + // if (lineNumber == null) { + // continue; + // } + // lineNumber = lineNumber - 1; + // if (ins.diff_kind !== DiffKind.DIFF_NONE) { + // if (currentRange !== null) { + // currentRange.end = lineNumber; + // } else { + // currentRange = { + // start: lineNumber, + // end: lineNumber, + // }; + // } + // } else if (currentRange !== null && lineNumber > currentRange.end) { + // lineRanges.push(currentRange); + // currentRange = null; + // } + // } + // if (currentRange !== null) { + // lineRanges.push(currentRange); + // } + // } + // } + // console.log('lineRanges', lineRanges); + // vscode.postMessage({ type: 'lineRanges', data: lineRanges }); - useDiffStore.setState({ diff }); + useExtensionStore.setState({ diff }); + } else if (message.type === 'task') { + if (message.taskType === 'build') { + useExtensionStore.setState({ buildRunning: message.running }); + } else { + console.error('Unknown task type', message.taskType); } + } else if (message.type === 'state') { + useExtensionStore.setState({ + configLoaded: message.configLoaded, + currentFile: message.currentFile, + }); + } else { + console.error('Unknown message', message); } });