-
Notifications
You must be signed in to change notification settings - Fork 4
Break #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Break #6
Changes from 9 commits
44e7e63
8162b3a
e0bfd1e
41ebadc
29b402b
20df943
2bbf0d3
da0524e
cc658ae
cb2140f
c1b36c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "log" | ||
|
|
||
| "github.com/emicklei/structexplorer" | ||
| ) | ||
|
|
||
| // go run . | ||
| func main() { | ||
| greeting := map[string]any{} | ||
| hello := struct{ Field string }{Field: "hello"} | ||
| greeting["hi"] = hello | ||
|
|
||
| log.Println("before opening the explorer to see state") | ||
|
|
||
| structexplorer.Break("map", greeting) | ||
|
|
||
| log.Println("after opening the explorer to see state") | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "log" | ||
| "testing" | ||
|
|
||
| "github.com/emicklei/structexplorer" | ||
| ) | ||
|
|
||
| func TestWithBreak(t *testing.T) { | ||
| target := struct{ Field string }{Field: "hello"} | ||
|
|
||
| log.Println("before opening the explorer to see state") | ||
|
|
||
| structexplorer.Break("debugging", target) | ||
|
|
||
| log.Println("after opening the explorer to see state") | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package structexplorer | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os/exec" | ||
| "runtime" | ||
| ) | ||
|
|
||
| // Open calls the OS default program for uri | ||
| func open(uri string) error { | ||
| switch { | ||
| case "windows" == runtime.GOOS: | ||
| return exec.Command("rundll32", "url.dll,FileProtocolHandler", uri).Start() | ||
| case "darwin" == runtime.GOOS: | ||
| return exec.Command("open", uri).Start() | ||
| case "linux" == runtime.GOOS: | ||
| return exec.Command("xdg-open", uri).Start() | ||
| default: | ||
| return fmt.Errorf("unable to open uri:%v on:%v", uri, runtime.GOOS) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -13,8 +13,18 @@ function explore(row, column, selectNode, action) { | |||||
| action: action, | ||||||
| selections: getSelectValues(selectNode) | ||||||
| })); | ||||||
| xhr.onload = function () { window.location.reload(); } | ||||||
| xhr.onload = function() { window.location.reload(); } | ||||||
| } | ||||||
|
|
||||||
| function resume() { | ||||||
| const xhr = new XMLHttpRequest(); | ||||||
| xhr.open("POST", window.location.href); | ||||||
| xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8") | ||||||
|
||||||
| xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8") | |
| xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||
| package structexplorer | ||||||||||
|
|
||||||||||
| import ( | ||||||||||
| "context" | ||||||||||
| _ "embed" | ||||||||||
| "encoding/json" | ||||||||||
| "fmt" | ||||||||||
|
|
@@ -18,8 +19,11 @@ type Service interface { | |||||||||
| // Start accepts 0 or 1 Options | ||||||||||
| Start(opts ...Options) | ||||||||||
|
|
||||||||||
| // Break accepts 0 or 1 Options | ||||||||||
| Break(opts ...Options) | ||||||||||
|
|
||||||||||
| // Dump writes an HTML file for displaying the current state of the explorer and its entries. | ||||||||||
| Dump() | ||||||||||
| Dump(optionFilename ...string) | ||||||||||
|
|
||||||||||
| // Explore adds or replaces (matching on label) a new entry for a value unless it cannot be explored. | ||||||||||
| // The object will be placed on the next available column on row 1. | ||||||||||
|
|
@@ -44,6 +48,7 @@ func (s *service) init() { | |||||||||
| type service struct { | ||||||||||
| explorer *explorer | ||||||||||
| indexTemplate *template.Template | ||||||||||
| httpServer *http.Server | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // NewService creates a new to explore one or more values (structures). | ||||||||||
|
|
@@ -53,6 +58,45 @@ func NewService(labelValuePairs ...any) Service { | |||||||||
| return s | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Break will listen and serve on the default endpoint and opens a window. | ||||||||||
| // The explorer page will have a button "Resume" that stops the server | ||||||||||
| // and unblocks the go-routine that started it. | ||||||||||
| func Break(keyvaluePairs ...any) { | ||||||||||
| NewService(keyvaluePairs...).Break(Options{ | ||||||||||
| ServeMux: new(http.ServeMux), | ||||||||||
| }) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Break will listen and serve on the given http port and path. | ||||||||||
| // it accepts 0 or 1 Options to override defaults. | ||||||||||
| // The opened explorer page will have a button "Resume" that stops the server | ||||||||||
| // and unblocks the go-routine that started it. | ||||||||||
| func (s *service) Break(opts ...Options) { | ||||||||||
| if len(opts) > 0 { | ||||||||||
| s.explorer.options = &opts[0] | ||||||||||
| } | ||||||||||
| port := s.explorer.options.httpPort() | ||||||||||
| serveMux := s.explorer.options.serveMux() | ||||||||||
| rootPath := s.explorer.options.rootPath() | ||||||||||
| serveMux.Handle(rootPath, s) | ||||||||||
| server := &http.Server{ | ||||||||||
| Addr: fmt.Sprintf(":%d", port), | ||||||||||
| Handler: serveMux, | ||||||||||
| } | ||||||||||
| s.httpServer = server | ||||||||||
| open(fmt.Sprintf("http://localhost:%d", port)) | ||||||||||
|
||||||||||
| open(fmt.Sprintf("http://localhost:%d", port)) | |
| if err := open(fmt.Sprintf("http://localhost:%d", port)); err != nil { | |
| slog.Error("failed to open browser", "err", err) | |
| } |
Copilot
AI
Oct 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return value of ListenAndServe() should be checked. If the server fails to start, the error will be ignored and the function will return silently, potentially leaving the caller in an unexpected state.
| server.ListenAndServe() | |
| if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { | |
| slog.Error("server failed", "err", err) | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space in error message format string.