diff --git a/.github/workflows/build-vsix.yml b/.github/workflows/build-vsix.yml new file mode 100644 index 0000000..fd9b441 --- /dev/null +++ b/.github/workflows/build-vsix.yml @@ -0,0 +1,91 @@ +name: Publish VSIX + +on: + push: + tags: + - v* + +jobs: + build: + name: Build VSIX + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup MSBuild (add to PATH) + uses: microsoft/setup-msbuild@v2 + - name: Locate MSBuild + id: msbuild + shell: pwsh + run: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if(-not (Test-Path $vswhere)) { throw "vswhere not found at $vswhere" } + $msbuild = & $vswhere -latest -requires Microsoft.Component.MSBuild -find "MSBuild\**\Bin\MSBuild.exe" | Select-Object -First 1 + if(-not $msbuild){ throw 'MSBuild not found' } + "path=$msbuild" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 + - name: Restore (solution) + shell: pwsh + run: | + dotnet restore src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtension.sln + - name: Build VSIX (Release) + shell: pwsh + run: | + & '${{ steps.msbuild.outputs.path }}' src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtension.csproj /t:Build /p:Configuration=Release /nologo + - name: Locate VSIX + id: locate_vsix + shell: pwsh + run: | + $outDir = "src/CodeIndex.VisualStudioExtension/bin/Release" + if(-not (Test-Path $outDir)) { throw "Output directory not found: $outDir" } + Write-Host "Listing VSIX output directory contents:"; Get-ChildItem -Path $outDir | Format-Table Name,Length,LastWriteTime + $vsix = Get-ChildItem -Path $outDir -Filter *.vsix -File | Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if(-not $vsix) { + Write-Host 'No VSIX found; dumping recursive tree:' + Get-ChildItem -Path $outDir -Recurse | Select-Object FullName,Length,LastWriteTime | Format-Table -AutoSize + throw 'VSIX file not generated.' + } + Write-Host "Found VSIX: $($vsix.FullName)" + if(-not (Test-Path 'artifacts')) { New-Item -ItemType Directory -Path artifacts | Out-Null } + $dest = Join-Path -Path (Resolve-Path 'artifacts').Path -ChildPath $vsix.Name + Copy-Item -Path $vsix.FullName -Destination $dest -Force -ErrorAction Stop + Write-Host "Copied to $dest" + "path=$dest" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: CodeIndex.VSIX + path: ${{ steps.locate_vsix.outputs.path }} + if-no-files-found: error + + release: + name: Create / Update Release + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: CodeIndex.VSIX + path: downloaded + - name: List downloaded files + run: ls -R downloaded + - name: Create or update release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + tag="$GITHUB_REF_NAME" + asset=$(ls downloaded/*.vsix | head -n1) + if [ -z "$asset" ]; then + echo "No VSIX asset found" >&2 + exit 1 + fi + echo "Publishing release $tag with asset $asset" + if gh release create "$tag" "$asset" --title "VSIX $tag" --notes "VSIX build for $tag" -R "$GITHUB_REPOSITORY"; then + echo "Release created" + else + echo "Release exists, updating asset..." + gh release upload "$tag" "$asset" --clobber -R "$GITHUB_REPOSITORY" + fi diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9f7b8c9..f51c37b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -46,9 +46,9 @@ jobs: Write-Host "Tag $tag deleted to prevent release." build: - name: Build & Package (framework-dependent any-platform) + name: Build & Package needs: test - runs-on: ubuntu-latest + runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v4 @@ -67,15 +67,16 @@ jobs: -p:PublishSingleFile=false -p:SelfContained=false -o artifacts/publish-any - name: Package zip + shell: pwsh run: | - mkdir -p artifacts/zips - (cd artifacts/publish-any && zip -r ../zips/CodeIndex.Server-any.zip .) + New-Item -ItemType Directory -Path artifacts/zips -Force | Out-Null + Compress-Archive -Path artifacts/publish-any/* -DestinationPath artifacts/zips/CodeIndex.Server.zip -Force - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: CodeIndex.Server-any - path: artifacts/zips/CodeIndex.Server-any.zip + name: CodeIndex.Server + path: artifacts/zips/CodeIndex.Server.zip if-no-files-found: error release: @@ -88,7 +89,7 @@ jobs: - name: Download artifact uses: actions/download-artifact@v4 with: - name: CodeIndex.Server-any + name: CodeIndex.Server path: downloaded - name: List downloaded files @@ -100,9 +101,9 @@ jobs: shell: bash run: | tag="$GITHUB_REF_NAME" - asset="downloaded/CodeIndex.Server-any.zip" - echo "Publishing release $tag with asset $asset (framework-dependent build)" - if gh release create "$tag" "$asset" --title "CodeIndex.Server $tag" --notes "Framework-dependent (cross-platform) build for $tag" -R "$GITHUB_REPOSITORY"; then + asset="downloaded/CodeIndex.Server.zip" + echo "Publishing release $tag with asset $asset" + if gh release create "$tag" "$asset" --title "CodeIndex.Server $tag" --notes "Framework-dependent build (.exe) for $tag" -R "$GITHUB_REPOSITORY"; then echo "Release created" else echo "Release exists, updating asset..." diff --git a/README.md b/README.md index 594a7ea..0a34dfa 100644 --- a/README.md +++ b/README.md @@ -93,11 +93,53 @@ Notice: in the docker container, when add the index config, the monitor folder s ### Search Extension For Visual Studio -|Status|Value| +Current icon used in listing: + +![Marketplace Icon](doc/Extension-Icon.png) + +|Status|Badge| |:----|:---:| -|VS Marketplace|[![VS Marketplace](http://vsmarketplacebadge.apphb.com/version-short/qiuhaotc.CodeIndexExtension.svg)](https://marketplace.visualstudio.com/items?itemName=qiuhaotc.CodeIndexExtension) -|VS Marketplace Downloads|[![VS Marketplace Downloads](http://vsmarketplacebadge.apphb.com/downloads/qiuhaotc.CodeIndexExtension.svg)](https://marketplace.visualstudio.com/items?itemName=qiuhaotc.CodeIndexExtension) -|VS Marketplace Installs|[![VS Marketplace Installs](http://vsmarketplacebadge.apphb.com/installs-short/qiuhaotc.CodeIndexExtension.svg)](https://marketplace.visualstudio.com/items?itemName=qiuhaotc.CodeIndexExtension) +|VS Marketplace Version|[![VS Marketplace Version](https://img.shields.io/visual-studio-marketplace/v/qiuhaotc.CodeIndexExtension?label=version&logo=visualstudio&color=blueviolet)](https://marketplace.visualstudio.com/items?itemName=qiuhaotc.CodeIndexExtension)| +|VS Marketplace Downloads|[![VS Marketplace Downloads](https://img.shields.io/visual-studio-marketplace/d/qiuhaotc.CodeIndexExtension?label=downloads&logo=visualstudio)](https://marketplace.visualstudio.com/items?itemName=qiuhaotc.CodeIndexExtension)| +|VS Marketplace Installs|[![VS Marketplace Installs](https://img.shields.io/visual-studio-marketplace/i/qiuhaotc.CodeIndexExtension?label=installs&logo=visualstudio)](https://marketplace.visualstudio.com/items?itemName=qiuhaotc.CodeIndexExtension)| +|VS Marketplace Rating|[![VS Marketplace Rating](https://img.shields.io/visual-studio-marketplace/r/qiuhaotc.CodeIndexExtension?label=rating&logo=visualstudio)](https://marketplace.visualstudio.com/items?itemName=qiuhaotc.CodeIndexExtension)| + +#### Recent Updates + +Latest improvements to the Visual Studio extension + +- Dual Server Modes + - Seamlessly switch between Local and Remote server modes with persistent settings. + - Automatic health probe on settings window open (local mode) + manual Check button. +- Resilient Local Server Lifecycle + - Single-instance control (global mutex + per-process lock files + PID file). + - Auto restart if external termination detected (mutex loss recovery). + - Deferred index loading until server health passes. +- Download / Update Workflow + - One-click Download / Update (latest tag scraped from Releases page). + - Streamed download with real-time percentage progress. + - Temp ZIP cleanup after successful extraction; validates core binary presence. +- Smart Default Paths + - Auto install path: `%LOCALAPPDATA%/CodeIndex.VisualStudioExtension/CodeIndex.Server` when empty. + - Auto data path: `%LOCALAPPDATA%/CodeIndex.VisualStudioExtension/CodeIndex.Server.Data` when first selecting install path and data path empty. +- Modern Folder Picker + - Replaced WinForms dialog with Vista IFileOpenDialog (better UX); removed System.Windows.Forms dependency. +- Theme-Aware UI + - Buttons/styles now use Visual Studio dynamic theme brushes (light/dark/HC) instead of hardcoded colors. +- Quick Navigation Buttons + - Open buttons beside Local & Remote URLs (auto prepend http:// when missing). +- Responsive Async Commands + - Instant button enable/disable; removed unsafe async void patterns. +- Embedded Log Viewer + - Displays latest 100 log lines with refresh. +- Packaging & Manifest Reliability + - Pre-build sync of `source.extension.vsixmanifest` prevents stale version drift. + - Architecture targeting + ProductArchitecture resolves VSSDK1311 warning. +- Settings & Migration + - JSON settings, legacy URL migration, normalized trailing slashes. +- Additional Hardening + - Clear health states (Started / Stopped / Error / Unknown) drive UI state. + - Improved error messages for download / extraction / URL opening. #### Download Url @@ -127,13 +169,19 @@ When Phase Quuery not been ticked, you can follow the sytax under [http://www.lu When Case-Sensitive been ticked, we can search the content in case-sensitive mode. When search the content like String, it won't return the content that contains string +## Extension Compile + +```powershell +& "C:\Program Files\Microsoft Visual Studio\18\Insiders\MSBuild\Current\Bin\MSBuild.exe" src\CodeIndex.VisualStudioExtension\CodeIndex.VisualStudioExtension.csproj /t:Build /p:Configuration=Debug /nologo +``` + ## Misc |Status|Value| |:----|:---:| -|Stars|[![Stars](https://img.shields.io/github/stars/qiuhaotc/CodeIndex)](https://github.com/qiuhaotc/CodeIndex) -|Forks|[![Forks](https://img.shields.io/github/forks/qiuhaotc/CodeIndex)](https://github.com/qiuhaotc/CodeIndex) -|License|[![License](https://img.shields.io/github/license/qiuhaotc/CodeIndex)](https://github.com/qiuhaotc/CodeIndex) -|Issues|[![Issues](https://img.shields.io/github/issues/qiuhaotc/CodeIndex)](https://github.com/qiuhaotc/CodeIndex) -|Docker Pulls|[![Downloads](https://img.shields.io/docker/pulls/qiuhaotc/codeindex.svg)](https://hub.docker.com/r/qiuhaotc/codeindex) -|Release Downloads|[![Downloads](https://img.shields.io/github/downloads/qiuhaotc/CodeIndex/total.svg)](https://github.com/qiuhaotc/CodeIndex/releases) +|Stars|[![Stars](https://img.shields.io/github/stars/qiuhaotc/CodeIndex)](https://github.com/qiuhaotc/CodeIndex)| +|Forks|[![Forks](https://img.shields.io/github/forks/qiuhaotc/CodeIndex)](https://github.com/qiuhaotc/CodeIndex)| +|License|[![License](https://img.shields.io/github/license/qiuhaotc/CodeIndex)](https://github.com/qiuhaotc/CodeIndex)| +|Issues|[![Issues](https://img.shields.io/github/issues/qiuhaotc/CodeIndex)](https://github.com/qiuhaotc/CodeIndex)| +|Docker Pulls|[![Downloads](https://img.shields.io/docker/pulls/qiuhaotc/codeindex.svg)](https://hub.docker.com/r/qiuhaotc/codeindex)| +|Release Downloads|[![Downloads](https://img.shields.io/github/downloads/qiuhaotc/CodeIndex/total.svg)](https://github.com/qiuhaotc/CodeIndex/releases)| diff --git a/doc/UseExtension.gif b/doc/UseExtension.gif index 0a5f914..ed8a4b1 100644 Binary files a/doc/UseExtension.gif and b/doc/UseExtension.gif differ diff --git a/src/.vscode/launch.json b/src/.vscode/launch.json deleted file mode 100644 index 9b523bf..0000000 --- a/src/.vscode/launch.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceFolder}/CodeIndex.ConsoleApp/bin/Debug/netcoreapp3.1/CodeIndex.ConsoleApp.dll", - "args": [], - "cwd": "${workspaceFolder}/CodeIndex.ConsoleApp", - "console": "internalConsole", - "stopAtEntry": false - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command:pickProcess}" - } - ] -} \ No newline at end of file diff --git a/src/.vscode/tasks.json b/src/.vscode/tasks.json deleted file mode 100644 index 3966d7a..0000000 --- a/src/.vscode/tasks.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "command": "dotnet", - "type": "process", - "args": [ - "build", - "${workspaceFolder}/CodeIndex.ConsoleApp/CodeIndex.ConsoleApp.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "publish", - "command": "dotnet", - "type": "process", - "args": [ - "publish", - "${workspaceFolder}/CodeIndex.ConsoleApp/CodeIndex.ConsoleApp.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "watch", - "command": "dotnet", - "type": "process", - "args": [ - "watch", - "run", - "${workspaceFolder}/CodeIndex.ConsoleApp/CodeIndex.ConsoleApp.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtension.csproj b/src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtension.csproj index 51148ba..c001715 100644 --- a/src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtension.csproj +++ b/src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtension.csproj @@ -9,15 +9,14 @@ false - bin\Release\ - true - TRACE - prompt - pdbonly - true - true - true - + bin\Release\ + true + TRACE + prompt + pdbonly + true + true + Debug AnyCPU @@ -121,10 +120,42 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + + $(NoWarn);MSB4011 + + + + + + <_CodeIndexManifest Include="source.extension.vsixmanifest" Condition="Exists('source.extension.vsixmanifest')" /> + + + + + + + + + + \ No newline at end of file diff --git a/src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtensionPackage.cs b/src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtensionPackage.cs index 53f4c7b..d38a3f5 100644 --- a/src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtensionPackage.cs +++ b/src/CodeIndex.VisualStudioExtension/CodeIndex.VisualStudioExtensionPackage.cs @@ -43,12 +43,31 @@ public sealed class VisualStudioExtensionPackage : AsyncPackage /// A cancellation token to monitor for initialization cancellation, which can occur when VS is shutting down. /// A provider for progress updates. /// A task representing the async work of package initialization, or an already completed task if there is none. Do not return null from this method. + UserSettings loadedSettings; + protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { - // When initialized asynchronously, the current thread may be a background thread at this point. - // Do any initialization that requires the UI thread after switching to the UI thread. - await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - await CodeIndex.VisualStudioExtension.CodeIndexSearchWindowCommand.InitializeAsync(this); + // 后台线程:可以做不需要 UI 的初始化 + loadedSettings = UserSettingsManager.Load(); + // 注册实例(引用 + 确保启动) + await Models.LocalServerLauncher.RegisterInstanceAsync(loadedSettings); + + // 切换到 UI 线程再注册命令 + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await CodeIndexSearchWindowCommand.InitializeAsync(this); + } + + protected override void Dispose(bool disposing) + { + try + { + if (disposing && loadedSettings != null) + { + Models.LocalServerLauncher.UnregisterInstance(loadedSettings); + } + } + catch { } + base.Dispose(disposing); } #endregion diff --git a/src/CodeIndex.VisualStudioExtension/CodeIndexSearchWindowCommand.cs b/src/CodeIndex.VisualStudioExtension/CodeIndexSearchWindowCommand.cs index cba22a4..db01c9c 100644 --- a/src/CodeIndex.VisualStudioExtension/CodeIndexSearchWindowCommand.cs +++ b/src/CodeIndex.VisualStudioExtension/CodeIndexSearchWindowCommand.cs @@ -13,7 +13,7 @@ internal sealed class CodeIndexSearchWindowCommand /// /// Command ID. /// - public const int CommandId = 4129; + public const int CommandId = 4129; /// /// Command menu group (command set GUID). @@ -39,6 +39,7 @@ private CodeIndexSearchWindowCommand(AsyncPackage package, OleMenuCommandService var menuCommandID = new CommandID(CommandSet, CommandId); var menuItem = new MenuCommand(this.Execute, menuCommandID); commandService.AddCommand(menuItem); + } /// @@ -84,12 +85,14 @@ private void Execute(object sender, EventArgs e) { this.package.JoinableTaskFactory.RunAsync(async delegate { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); ToolWindowPane window = await this.package.ShowToolWindowAsync(typeof(CodeIndexSearchWindow), 0, true, this.package.DisposalToken); - if ((null == window) || (null == window.Frame)) + if (window?.Frame == null) { throw new NotSupportedException("Cannot create tool window"); } - }); + }).FileAndForget("CodeIndex/ShowToolWindow"); } + } } diff --git a/src/CodeIndex.VisualStudioExtension/Controls/CodeIndexSearchControl.xaml b/src/CodeIndex.VisualStudioExtension/Controls/CodeIndexSearchControl.xaml index 1167312..7645863 100644 --- a/src/CodeIndex.VisualStudioExtension/Controls/CodeIndexSearchControl.xaml +++ b/src/CodeIndex.VisualStudioExtension/Controls/CodeIndexSearchControl.xaml @@ -3,10 +3,18 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0" mc:Ignorable="d" - d:DesignHeight="281.2" d:DesignWidth="987.2" Foreground="Black" Background="#FF2D2D30"> + d:DesignHeight="281.2" d:DesignWidth="987.2" + Foreground="{DynamicResource {x:Static vsshell:VsBrushes.WindowTextKey}}" + Background="{DynamicResource {x:Static vsshell:VsBrushes.ToolWindowBackgroundKey}}"> - + + + + + + @@ -44,18 +52,17 @@ - - -