Adds OutlineHandler.cs to the Roslyn helper using CSharpSyntaxTree.ParseText and manual syntax tree traversal (no solution load required). Extracts namespaces, types, method/property/field/event signatures and line numbers without method bodies. Handles file-scoped namespaces, generics, records, nested types, partial classes, top-level statements, and [Obsolete] markers. Adds Microsoft.CodeAnalysis.CSharp 4.13.0 as the sole new NuGet dependency (pure parser, no MSBuild coupling). Go side adds Outline() client method, OutlineResult/Type/Member types, outline.go command, and WriteOutline formatter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
1.6 KiB
Go
69 lines
1.6 KiB
Go
package csharp
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
|
||
"github.com/ricarneiro/ctx/internal/core"
|
||
"github.com/ricarneiro/ctx/internal/plugins/csharp/helper"
|
||
"github.com/spf13/cobra"
|
||
)
|
||
|
||
func outlineCmd(ctx *core.Context) *cobra.Command {
|
||
return &cobra.Command{
|
||
Use: "outline <file.cs>",
|
||
Short: "Show structural outline of a C# file (no method bodies)",
|
||
Long: `Parse a C# source file and emit its structural skeleton:
|
||
namespaces, types, method signatures, properties, fields, events.
|
||
Method bodies are omitted — reduces large files by 80–90%.
|
||
|
||
Does not require a loaded solution. Works on a single file.`,
|
||
Args: cobra.ExactArgs(1),
|
||
RunE: func(cmd *cobra.Command, args []string) error {
|
||
return runOutline(ctx, args[0])
|
||
},
|
||
}
|
||
}
|
||
|
||
func runOutline(ctx *core.Context, file string) error {
|
||
abs, err := resolveFilePath(ctx.WorkDir, file)
|
||
if err != nil {
|
||
fmt.Fprintln(ctx.Stderr, err.Error())
|
||
return errExit
|
||
}
|
||
|
||
if !strings.HasSuffix(strings.ToLower(abs), ".cs") {
|
||
fmt.Fprintf(ctx.Stderr, "not a C# file: %s\n", abs)
|
||
return errExit
|
||
}
|
||
|
||
if _, err := os.Stat(abs); err != nil {
|
||
fmt.Fprintf(ctx.Stderr, "file not found: %s\n", abs)
|
||
return errExit
|
||
}
|
||
|
||
client, err := helper.NewClient()
|
||
if err != nil {
|
||
fmt.Fprintln(ctx.Stderr, err.Error())
|
||
return errExit
|
||
}
|
||
defer client.Close()
|
||
|
||
outline, err := client.Outline(abs)
|
||
if err != nil {
|
||
fmt.Fprintln(ctx.Stderr, err.Error())
|
||
return errExit
|
||
}
|
||
|
||
return WriteOutline(ctx.Stdout, outline)
|
||
}
|
||
|
||
func resolveFilePath(workDir, file string) (string, error) {
|
||
if filepath.IsAbs(file) {
|
||
return filepath.Clean(file), nil
|
||
}
|
||
return filepath.Clean(filepath.Join(workDir, file)), nil
|
||
}
|