-
-
Notifications
You must be signed in to change notification settings - Fork 2
preset: filename-handling, and names nobody can read shown as escapes #138
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
0d12bd4
recipe: a space from outside ASCII at the end of a value is kept
donislawdev 69e34f7
recipe: a character nobody can see is composed as an escape
donislawdev 9386d9c
cli: a name nobody can read is shown as an escape
donislawdev 73a6cfa
guard: no file in the repository carries a character nobody can see
donislawdev 6eb1c31
preset: a preset declares the default of a flag it reads
donislawdev 8c842f3
preset: filename-handling, fifty names a system did not expect
donislawdev e4a53c3
review: every message escapes a character nobody can see, and CI
donislawdev 8d77d2b
review: no second escape under a box, where nothing reaches it raw
donislawdev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| package core | ||
|
|
||
| import ( | ||
| "strconv" | ||
| "strings" | ||
| "unicode/utf8" | ||
| ) | ||
|
|
||
| // Shown is s the way a person should read it: every character HoldsUnseen | ||
| // finds, and every byte that is not UTF-8, written as the escape %q would use | ||
| // for it, and nothing else changed. No quotes are added. | ||
| // | ||
| // For every line this tool prints about a name or a path that came from a | ||
| // recipe, a preset, a manifest or a directory listing (O241). Measured on | ||
| // 2026-09-24: verify reported a missing "photo", right to left override, | ||
| // "gpj.txt" as the terminal drew it, which is "phototxt.jpg", and an extra | ||
| // "in", zero width space, "voice.txt" as "invoice.txt" - a report naming files | ||
| // other than the ones on the disk, two of which could not be told apart. | ||
| // | ||
| // Without quotes, because a name holding nothing of the kind comes out byte | ||
| // for byte as it always did, and every report line of every run that never | ||
| // met such a name stays what scripts and people already read. The escape is | ||
| // not ambiguous inside a file name: a backslash is refused in one on every | ||
| // system (engine/filename.go). In a Windows path it reads as a separator | ||
| // followed by a letter and a number, which a person does not mistake for one. | ||
| // | ||
| // Never for what a program reads. The manifest and every --json report carry | ||
| // the name exactly, because a program compares it byte for byte. | ||
| func Shown(s string) string { | ||
| if !HoldsUnseen(s) && utf8.ValidString(s) { | ||
| return s | ||
| } | ||
| return shown(s, false) | ||
| } | ||
|
|
||
| // ShownText is Shown for a whole message rather than one name: the line | ||
| // breaks and tabs it is laid out with stay as they are, and everything else | ||
| // nobody can see is escaped. | ||
| // | ||
| // For the places a message is turned into words for a person - the command | ||
| // line's describeError and the window's refusals - because an error wrapped | ||
| // from the operating system repeats the path it failed on in its own words, | ||
| // after this tool's sentence has already shown it. Measured on 2026-09-25, | ||
| // from a review: "cannot create the output directory" showed the folder | ||
| // escaped and the "mkdir" part after it showed it raw. | ||
| func ShownText(s string) string { | ||
| return shown(s, true) | ||
| } | ||
|
|
||
| func shown(s string, layout bool) string { | ||
| var b strings.Builder | ||
| for i := 0; i < len(s); { | ||
| r, size := utf8.DecodeRuneInString(s[i:]) | ||
| switch { | ||
| case r == utf8.RuneError && size == 1: | ||
| q := strconv.Quote(s[i : i+1]) | ||
| b.WriteString(q[1 : len(q)-1]) | ||
| case layout && (r == '\n' || r == '\t'): | ||
| b.WriteRune(r) | ||
| case !strconv.IsPrint(r): | ||
| q := strconv.QuoteRune(r) | ||
| b.WriteString(q[1 : len(q)-1]) | ||
| default: | ||
| b.WriteString(s[i : i+size]) | ||
| } | ||
| i += size | ||
| } | ||
| return b.String() | ||
| } | ||
|
|
||
| // ShownEach is Shown for every name of a list, for the lines that name a few | ||
| // files one after another. | ||
| func ShownEach(names []string) []string { | ||
| out := make([]string, len(names)) | ||
| for i, name := range names { | ||
| out[i] = Shown(name) | ||
| } | ||
| return out | ||
| } | ||
|
|
||
| // HoldsUnseen reports whether s holds a character a person reading it cannot | ||
| // see: a character that changes the direction of the text around it, one of | ||
| // no width, a byte order mark, a separator that breaks a line without being a | ||
| // line break, a space that is not the space bar's, a tag character, and every | ||
| // other one Go does not count as printable. | ||
| // | ||
| // It exists because file names are exactly where such characters are put on | ||
| // purpose. A name with a right to left override shows its extension in the | ||
| // wrong place, one with a zero width space prints as a name it is not, and | ||
| // both are test cases this tool writes (docs/NAMES-PRESET-2026-09-24.md). The | ||
| // file keeps its name. What a person reads about it has to show the character | ||
| // rather than let it act (O241), and a recipe has to carry it in a form that | ||
| // can be read and edited (O244). | ||
| // | ||
| // The class is strconv.IsPrint turned around, and that is a choice: it is the | ||
| // class %q escapes, and the refusals of this tool have quoted names with %q | ||
| // all along. One rule means one name looks the same in a refusal, in a report | ||
| // and in a recipe. A combining mark is printable and stays as it is. The | ||
| // space is printable, every other space is not. | ||
| func HoldsUnseen(s string) bool { | ||
| for _, r := range s { | ||
| if !strconv.IsPrint(r) { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.