mirror of
https://github.com/microsoft/terminal.git
synced 2026-02-03 21:25:34 +00:00
render: defer conversion of TextColor into COLORREF until actual rendering time (avoid ConPTY narrowing bugs) #3747
Closed
opened 2026-01-30 23:29:02 +00:00 by claunia
·
47 comments
No Branch/Tag Specified
main
dev/cazamor/bugfix/window-root-memory-leak
dev/lhecker/11509-kitty-keyboard-protocol-wip
automated/loc-update
feature/llm
dev/pabhoj/actions_editor_visual
dev/cazamor/selfhost/2026-01-29
dev/lhecker/11509-kitty-keyboard-protocol
dev/cazamor/sui/search
dev/duhowett/no-blank-issues-you-lost-privileges-for-that-fam
dev/lhecker/benchcat-fix
dev/lhecker/dcs-perf
dev/duhowett/eoy-25/allow-set-foreground
release-1.24
release-1.23
dev/cazamor/bot/deprecate-area-atlasengine
dev/pabhoj/actions_editor_followups
dev/cazamor/selfhost/2026-01-20
dev/cazamor/selfhost/2026-01-12
dev/cazamor/spec/auto-save
dev/duhowett/eoy-25/underline-colors-in-atlas-bug-redux
dev/duhowett/fhl-2024/asciicast-recorder
dev/duhowett/eoy-25/underline-colors-in-atlas-bug
dev/duhowett/hax/serial-port-support
dev/duhowett/connection-utf8
dev/lhecker/fused-event
dev/lhecker/18928-wip
dev/duhowett/fhl-2024/clang
dev/cazamor/uia-leak
dev/duhowett/win7-wpf-termcontrol-squash
release-1.22
dev/cazamor/selfhost/11-18-v3
dev/cazamor/selfhost/11-18
dev/duhowett/fhl-2025/bitmap-fonts
dev/duhowett/server-2025-vms
dev/duhowett/cant-believe-gotta-do-this-shit
dev/lhecker/1410-large-scrollback
dev/lhecker/dark-mode
dev/cazamor/sui/invert-cursor-color
dev/duhowett/fhl-2025/wt-command-palette-cmdpal-integration
dev/duhowett/fhl-2025/wt-json-relative-icons
dev/lhecker/fucking-service-locator
dev/duhowett/unicode-17
dev/duhowett/multi-blern
dev/lhecker/wellp2-alt
dev/duhowett/wellp2
dev/lhecker/1860-horizontal-scrollbar
dev/lhecker/fix-window-count
dev/cazamor/sui/tab-color-old
dev/duhowett/hax/conhost-icon
dev/duhowett/hax/sui-color-chip-border
dev/duhowett/hax/terminalsettings-as-a-lib-/with-types-merged-into-tsm
dev/pabhoj/page_control_input_cleanup
dev/duhowett/padding-in-atlas-rebase-20250729
dev/lhecker/attach-thread-input
dev/duhowett/portable-shader-members
msbuildcache-reenable
dev/cazamor/selfhost/1.24-2025-06-10
dev/cazamor/upgrade-settings-containers
dev/cazamor/sui/ext-page/powershell-stub
dev/cazamor/selfhost/1.24-2025-05-15
dev/pabhoj/sui_action_overhaul
dev/cazamor/selfhost/1.24-2025-05-06
dev/cazamor/selfhost/1.24-2025-04-29
dev/cazamor/sui/ext-page/lazy-load-objects
dev/cazamor/sui/ext-page/badge
dev/cazamor/selfhost/1.24
dev/lhecker/sdk-26100
dev/duhowett/testing
dev/jadelaga/VS-Pty.Net-1.22
dev/duhowett/fhl-2025/what-if-no-content-ids
dev/cazamor/a11y/vt-seq-prototype
dev/lhecker/18584-part2
dev/lhecker/get-lang-id
dev/duhowett/hax/clogs
release-1.21
dev/pabhoj/featurellm_fix_paste
dev/lhecker/grapheme-backup
dev/jadelaga/VS-Pty.netFixes
dev/lhecker/atlas-engine-compute-shader
dev/migrie/s/ai-providers
dev/lhecker/animated-cursor-wip
dev/pabhoj/featurellm_timeout
dev/lhecker/dark-mode-alt
dev/duhowett/osc-strided-table
dev/lhecker/bugbash
dev/pabhoj/featurellm_improve_parsing
dev/duhowett/coast-to-coast
dev/lhecker/curly-improvements
dev/duhowett/net8
dev/duhowett/onebranch-custom-pool
dev/lhecker/renderer-overhaul-2nd-attempt
dev/lhecker/cleanup
dev/cazamor/sui/confirmation-announcements
dev/lhecker/theme-quality
dev/duhowett/hax/cmake
dev/lhecker/winconpty-cleanup
dev/duhowett/learn/rewrite-highlights
dev/migrie/b/no-nesting-when-searching
release-1.20
dev/lhecker/14165-conhost-font-size
dev/duhowett/sel-2-spans
dev/lhecker/7118-cursor-color
dev/lhecker/remove-glyph-width
dev/lhecker/igfw-scroll-region
dev/lhecker/17656-win32im-double-encoding
dev/duhowett/fhl-2024/merge-idls
dev/duhowett/feed-forward-variables
dev/lhecker/remove-chrome-math
dev/duhowett/copylink
dev/duhowett/applicableactions
gh-readonly-queue/main/pr-17566-de50310295b7d92ed3d51f07974a2a945776bf9d
dev/lhecker/atlas-engine-stride-copy
dev/migrie/b/bump-nuget-in-c
dev/migrie/f/992-redux-redux
dev/migrie/f/filter-weight-input-too
dev/migrie/f/disable-nesting
dev/migrie/f/local-snippets-cleaner
dev/migrie/s/1553-mouse-bindings
selfhost-1.22-bugbash-2024-06-04
selfhost/1.22-bugbash-2024-06-04
dev/lhecker/15689-tab-drag-crash-fix
dev/migrie/f/sxnui-font-size-change
dev/migrie/f/local-snippets-on-action-refactor
dev/migrie/f/just-local-snippets
dev/migrie/save-input-patches
dev/migrie/f/md-pane-official
dev/migrie/base-pane
dev/migrie/fhl/tasks-pane
release-1.19
dev/migrie/b/17130-clear-marks-2
dev/migrie/b/17075-its-me-the-killer
dev/duhowett/i-figured-out-why-sometimes-the-publish-build-failed
dev/duhowett/nuget-publication-with-aad-app-id
selfhost-1.20
dev/duhowett/graph
dev/migrie/b/15803-activate-dont-copypasta
dev/duhowett/is-pgo-broken-because-of-sui-being-slower
dev/migrie/b/remove-terminaltab
dev/migrie/fhl/md-pane
dev/migrie/fhl/local-tasks-2024
dev/migrie/fhl/2024-inline-notebook
dev/duhowett/interface-projects
dev/duhowett/dead-loc
release-1.18
dev/migrie/fhl/2024-spring-merge-base
dev/duhowett/hax/l9
inbox
dev/migrie/14073-on-main
dev/duhowett/hax/conhost_dump_replay
user/lhecker/atlas-engine-srgb
dev/migrie/fhl/sxnui-tooltips-3
dev/migrie/7718-notifications-experiments
dev/migrie/fhl/7718-notifications
dev/migrie/fhl/7718-notifications-reboot
dev/lhecker/remove-gsl
dev/lhecker/16575-TerminateProcess
dev/lhecker/window-thread-climate-control
dev/lhecker/client-context-input-output-mode
dev/lhecker/ring-buffer-input-buffer
release-1.17
dev/lhecker/propsheet-fontdlg-refactor
dev/lhecker/renderer-overhaul
dev/pabhoj/test
dev/duhowett/chop
dev/lhecker/til-ulong-cleanup
dev/lhecker/til-env-cleanup
dev/migrie/f/16005-a11y-pane
dev/cazamor/a11y/fastpass
dev/migrie/b/15487-push-cwd
dev/migrie/b/15536-or-15219-idk
dev/duhowett/move-timers-down-into-core-interactivity-etc
dev/migrie/b/15812-broadcast-paste-two
dev/migrie/fhl-fall-2023/11162-quake-III-arena
dev/migrie/fhl-fall-2023/1620-automatic-tab-progress
dev/migrie/fhl-fall-2023/9992-quake-II
dev/migrie/fhl-fall-2023/9992-default-quake-settings
dev/migrie/fhl-fall-2023/9992-window-name-settings
dev/migrie/fhl-fall-2023/oceans
dev/lhecker/ColorScheme-improvements
dev/migrie/search-v2-v3
dev/migrie/pr-15717/its-dangerous-to-go-alone
dev/migrie/f/4768-taskbar-icons
dev/duhowett/padding-in-atlas
dev/migrie/f/3121-tooltips
dev/duhowett/sticky-control
dev/duhowett/fix-tracing-2
dev/migrie/b/add-support-for-vsc-marks
dev/migrie/f/1860-this-is-literally-what-less-is-for
dev/migrie/s/5916-draft
dev/lhecker/tracy
dev/migrie/s/north-star
dev/cazamor/tag-youre-it
dev/migrie/f/12336-let-it-mellow
dev/migrie/f/now-with-more-compat-settings
dev/migrie/f/compatibility-sui
dev/duhowett/hax/wpf-atlas
dev/duhowett/fgb
dev/migrie/b/15487-relative-paths-are-hard
dev/lhecker/colrv1
loc-update
dev/migrie/fhl/dyndep-csharp
dev/migrie/fhl/dyndep
dev/migrie/fhl-clickable-send-input
dev/migrie/f/cwd-hijinks-5506-15173
dev/lhecker/openconsole-async-start
1.17
dev/migrie/bump-scratch
dev/migrie/f/3726-restartConnection
dev/migrie/b/cxn-restarting-attempt-1-backport
dev/migrie/b/9053-part-3-the-actual-doing-of-the-thing
dev/migrie/b/13388-focus-logger
dev/migrie/b/9053-part-4-i-guess-defterm
dev/migrie/oop/3/of-the-silmarils
of-the-darkening-of-valinor
dev/migrie/fhl/notebook-proto-000
dev/migrie/f/narrator-buddy
dev/migrie/mux-2.8.2-march-2023
dev/migrie/f/roast-mutton
dev/migrie/f/12861-preview-input
dev/lhecker/clang-tidy
dev/migrie/f/3121-wE-dOnT-hAvE-dEv-DaYs
dev/duhowett/compiler-compliance
dev/duhowett/i-have-a-burning-hatred-for-ntstatus-of-later-so-why-not-fix-it
dev/duhowett/shorthand-namespaces
dev/duhowett/rename-all-dlls
dev/duhowett/errordialog
dev/lhecker/gsl-narrow
dev/migrie/b/11522-dumb-idea
release-1.16
dev/miniksa/env
dev/duhowett/hax/embed-everything
dev/migrie/b/13388-attempt-003
dev/migrie/b/14512-test-research
dev/migrie/b/13388-attempt-002
dev/migrie/b/14464-copyOnSelect-moving-text
dev/migrie/s/thema-schema-for-1.16
dev/migrie/s/theme-pair-schema
dev/migrie/b/13388-experiments-1
dev/cazamor/spec/a11y-vt-seq
dev/migrie/b/14557-empty-folder-dropdown
dev/cazamor/spec/a11y-vt-seq-v2
release-1.15
dev/migrie/f/process-model-v3-test-0
dev/lhecker/vsconfig
dev/migrie/s/5000-presentation
dev/lhecker/5907-startup-perf
dev/lhecker/winrt-file-api-benchmark
dev/duhowett/128-bit-compiler
dev/duhowett/hax/arm64-native-build
dev/migrie/fhl/more-shell-integration
dev/migrie/b/13388-experiments-0
dev/lhecker/til-to-ulong-improvements
dev/migrie/s/markdown-notebooks
dev/cazamor/a11y/nav-by-page
dev/cazamor/a11y/system-menu-support
dev/duhowett/no-private-registry-keys
dev/cazamor/wpf/uia-expose-enable-events
dev/cazamor/wpf/uia-events
extendAISpec
dev/migrie/fhl/clickSendInput
dev/migrie/fhl/save-command
dev/migrie/b/theme.profile
dev/migrie/b/13943-a-test-for-this
dev/migrie/oop/2/endgame
dev/duhowett/hax/merge_idl
dev/migrie/oop/2/infinity-war
dev/migrie/spellbot-cve
dev/cazamor/a11y-sev3/new-profile-announcement
dev/migrie/fhl/upside-down-mode
release-1.14
dev/migrie/f/9458-startupInfoToTerminal
dev/migrie/fhl/5916-triggers
dev/migrie/b/13523-context-menu
dev/migrie/b/6523-endpaint-outside-lock
dev/migrie/b/12413-OnUnhandledException
dev/lhecker/render-snapshot
dev/cazamor/1.15/scroll-to-point
dev/migrie/mux-2.8-aug-2022
dev/lhecker/lock-console-guard
dev/migrie/f/1504-final
dev/pabhoj/sui_follow_ups
dev/migrie/f/til-winrt.h
dev/cazamor/color-picker-redesign
dev/migrie/fhl/vscode-autocomplete-prototype
dev/migrie/f/1504-prototype
dev/migrie/oop/2/loki
dev/migrie/oop/2/wandavision
dev/migrie/b/8698-YOURE-OUT-OF-ORDER
fabricbot-configuration-migration
dev/migrie/b/12788-did-it-work
dev/migrie/b/localtests-ci-2022
dev/cazamor/1.14/replace-compareInBounds
dev/pabhoj/preview_string
dev/cazamor/ks/switchSelectionEndpoint
dev/migrie/oop/2/COM-ISwapChainProvider-attempt-1
dev/migrie/b/dxd-marker
release-1.13
dev/migrie/b/13066-for-defterm
dev/cazamor/revert-dwm
dev/migrie/b/13066-sw_flash_repeatedly
dev/migrie/b/no-cloaky-cloak
dev/migrie/f/apples-to-oranges
dev/migrie/f/no-custom-caption-btns
dev/migrie/f/10509-mica-and-transparent-titlebars
dev/migrie/b/12911-wpf-focus-fg
dev/migrie/titebar-colors
dev/lhecker/4015-cursor
dev/migrie/fhl/rgb-rainbow-window-frame
dev/migrie/fhl/scroll-marks-prototype
release-1.12
dev/miniksa/compliance
dev/migrie/f/default-icons
dev/migrie/fhl/10175-web-search-for-text
dev/migrie/fhl/menu-complete-prototype
dev/migrie/b/2988-merged-prototypes
dev/migrie/b/2988-niksa-msgs-prototype
dev/migrie/fhl/9583-colorSelection
dev/migrie/b/10609-sui-leak
dev/migrie/b/32-attempt-3
dev/migrie/release-1.12-rejuv-attempt-2
dev/migrie/demo-for-presentation
dev/migrie/b/32-but-im-here-for-12567
dev/duhowett/conpty_first_frame_blug
dev/migrie/b/11092-unfocused-acrylic-settings
dev/migrie/localtests-in-ci
dev/migrie/b/12356-attempt-2
dev/migrie/b/12353-with-null
dev/migrie/b/12387-trim-spaces
dev/migrie/b/5033-bad-start
dev/lhecker/12351-broken-locales
dev/migrie/b/8663-input-to-oem-crash
dev/migrie/b/11743-win10-opacity-is-hard
dev/migrie/f/ctrl-click-elevate
dev/migrie/b/12196-shim-localization
dev/lhecker/issue-4015-til-rect
dev/cazamor/eim/mvvm
dev/migrie/f/--elevate
dev/migrie/b/11668-i-think
dev/migrie/b/11994-wsl-mangline
dev/migrie/eim/3475-action-xmacros
dev/migrie/eim/incremental-build-000
dev/cazamor/a11y/fake-uia-data
dev/migrie/f/non-terminal-content-elevation-warning
dev/migrie/f/632-on-warning-dialog
dev/lhecker/rgba
dev/migrie/b/8480-keybindings-in-tabs
release-1.11
dev/migrie/b/11561-dead-ends
dev/migrie/oct-21-roadmap-update
dev/migrie/fhl/adaptive-card-extension
dev/cazamor/test/11440
dev/migrie/f/warning-dlg-automation
dev/migrie/b/1.12-crash-on-exit
dev/migrie/b/11146-next-tab-in-cmdpal
release-1.10
dev/migrie/5ff9a24-and-75e2b5f
dev/duhowtt/hax/cpal-jumplist-async
dev/lelian/actionid/1
dev/migrie/f/just-elevated-state
dev/lhecker/terminal-settings-cleanup
dev/migrie/gh-10824
dev/pabhoj/cursor_light
dev/migrie/oop/wandavision
dev/migrie/oop/endgame
dev/migrie/oop/infinity-war
dev/lhecker/app-state-actually-hidden
dev/migrie/b/6160-dynamic-default-warning
dev/mgirie/b/more-nchhittest-ideas
dev/migrie/b/9320-interfacial-separation
cinnamon/fhl/find-contextmenu
dev/lhecker/wsl-distro-generator-cleanup
dev/migrie/b/10875-but-more-clever
dev/migrie/b/broken-globalsummon-overloading
dev/duhowett/hax/rle-row
dev/migrie/fhl-2021/cmdpal-select-list
dev/migrie/fhl-2021/differential-pixel-shading
dev/duhowett/hax/no-writable-glyphat
dev/migrie/fhl-2021/more-shader-variables
dev/migrie/titlebar-shenannigans
dev/miniksa/win10_font_matching
dev/lhecker/conhost-oom
dev/migrie/b/10332-less-snappy-scrolling
dev/migrie/b/7422-1px-top-border
release-1.9
dev/cazamor/move-scratch
release-1.8
dev/miniksa/manifest_2
release-1.6
release-1.7
dev/migrie/oop/the-whole-thing
dev/migrie/oop/connection-factory
dev/migrie/f/quake-dropdown-2
dev/miniksa/rle2
dev/migrie/f/quake-toCurrent-experiments-2
dev/migrie/f/quake-toCurrent-experiments
dev/migrie/f/quake-dropdown
dev/cazamor/actions-page/template
dev/duhowett/hax/cursor_stamp_foreground_background
dev/migrie/f/1860-hey-might-was-well-hack-during-a-hackathon
dev/migrie/oop-terminal.control-split-control
dev/duhowett/hax/build-with-wholearchive
dev/cazamor/spec/tsm-actions-temp
dev/migrie/oop-tear-apart-control
dev/migrie/oop-scratch-3
dev/cazamor/sui/bugfix-reload-crash
dev/migrie/f/xmacro
dev/cazamor/sui/proto/profile-nav-view
dev/migrie/f/name-windows
dev/migrie/dol/messing-with-shaders-take-1
release-1.5
dev/cazamor/sui/inheritance-hyperlinks-test
dev/migrie/r/commandline-lib-002
dev/migrie/f/com.fabrikam.toaster
dev/cazamor/adaptive-cards-prototype
dev/migrie/f/commandline-lib
dev/miniksa/zipzoom2
dev/migrie/f/remote-commandlines
dev/migrie/f/632-elevated-profiles
dev/migrie/oop-broker-000
dev/migrie/fix-pr-7015
dev/duhowett/clang
dev/miniksa/input_tests_2
dev/miniksa/input2
dev/migrie/oop-rpc-000
release-1.4
dev/migrie/oop-mixed-elevation-1
dev/migrie/oop-window-content-1
cinnamon/open-json
dev/miniksa/input_tests
dev/duhowett/hax/tsm-graphviz
dev/miniksa/input
dev/duhowett/hax/caption_buttons
release-1.3
dev/cazamor/a11y/expand-line-under-viewport
dev/cazamor/acc/ch/word-nav-perf
dev/cazamor/spec/settings-ui-architecture-draft
dev/duhowett/hax/tap_upgrade
dev/migrie/f/pane-exit-animation
release-1.2
dev/migrie/move-lib-up-and-dll-down
release-1.1
dev/migrie/f/branch-2-backup
dev/migrie/f/settings-getters-only
dev/duhowett/hax/command_palette_search
dev/migrie/f/6856-let-terminalpage-expandcommands
dev/migrie/f/theming-2020
dev/migrie/oop-scratch-4
dev/duhowett/hax/punchout
dev/migrie/s/action-ids
dev/migrie/f/lets-just-generate-these
dev/migrie/oop-scratch-2
dev/miniksa/dcomp
dev/miniksa/gotta_go_fast_spsc
dev/miniksa/gotta_go_fast
dev/miniksa/perf_skip_checks
dev/miniksa/perf_buffer_dig
dev/migrie/s/1203-cursorTextColor
dev/migrie/f/fix-intellisense-i-guess-backup
release-1.0
dev/migrie/f/execute-commandlines
dev/migrie/f/2046-Command-Palette-v2
dev/migrie/b/6421-passthrough-alt
dev/migrie/b/moving-focus-is-hard
dev/miniksa/set
dev/migrie/f/1203-phase-1
dev/migrie/f/get-localtests-in-ci
dev/cazamor/drag-panes
dev/cazamor/tile-background
release-0.11
dev/duhowett/dev/duhowett/hax/appstate_remember
dev/duhowett/load_condrv
dev/duhowett/hax/wpf_win_8_hax
dev/migrie/b/3088-weird-exact-wrap-resize
release-0.10
dev/migrie/b/4591-custom-scaling-bug
dev/duhowett/hax/attr_smuggling
dev/migrie/b/5161-mingw-vim-fix
dev/miniksa/dx_bitmap
dev/migrie/b/1503-try-messing-with-cooked-read
dev/duhowett/eyebeam
dev/migrie/b/5113-experiments
dev/duhowett/hax-selection-exclusive
dev/migrie/f/more-vt-renderer-tracing
dev/miniksa/bitmap
dev/duhowett/wprp
dev/miniksa/bitmap-mad-with-power
dev/migrie/f/resize-quirk
dev/migrie/f/reflow-buffer-on-resize-002
wpf-renderer-revert
dev/miniksa/draw
release-0.9
dev/miniksa/tabs-color-fix
dev/miniksa/4309
dev/migrie/f/just-wrapping
dev/migrie/b/3490-try-another-resize-algo
release-0.8
dev/migrie/b/3490-a-simpler-resize
dev/migrie/b/3490-resize-down
dev/miniksa/4254
dev/migrie/f/conpty-wrapped-lines-2
dev/migrie/b/be-better-at-hiding
dev/migrie/f/3327-xaml-theming-proto
dev/miniksa/gardening2
release-0.7
dev/duhowett/conpty-flags
dev/migrie/f/603-vintage-opacity
dev/migrie/PR#3181-comments
dev/duhowett/font-64
release-0.5
dev/migrie/b/663-paste-lf-always
dev/migrie/b/2011-reordered-fallthrough-strings
dev/migrie/b/411-init-tab-stops
dev/migrie/b/json-patching-is-hard
dev/migrie/b/2455-try-getting-tests-working
dev/migrie/b/1223-change-256-table
dev/migrie/f/2171-openterm.cmd
dev/migrie/f/drag-panes
dev/migrie/f/2046-command-palette
release-0.3
dev/miniksa/manager
dev/migrie/f/non-terminal-panes
dev/migrie/f/passthrough-2019
dev/miniksa/shared_pch
dev/migrie/f/1897-less-duplicated-work
release-0.2
dev/cazamor/mcs/viewport-selection
dev/duhowett/version_hack
v1.24.10212.0
v1.23.20211.0
v1.24.3504.0
v1.23.13503.0
v1.24.2812.0
v1.23.12811.0
v1.24.2682.0
v1.23.12681.0
v1.24.2372.0
v1.23.12371.0
v1.23.12102.0
v1.22.12111.0
v1.23.11752.0
v1.22.11751.0
v1.22.11141.0
v1.23.11132.0
v1.23.10732.0
v1.22.10731.0
v1.21.10351.0
v1.22.10352.0
v1.23.10353.0
v1.22.3232.0
v1.21.3231.0
v1.22.2912.0
v1.21.2911.0
v1.22.2702.0
v1.21.2701.0
v1.22.2362.0
v1.21.2361.0
v1.21.1772.0
v1.20.11781.0
v1.21.1382.0
v1.20.11381.0
v1.21.1272.0
v1.20.11271.0
v1.20.11215.0
v1.19.11213.0
v1.20.10822.0
v1.19.10821.0
v1.20.10572.0
v1.19.10573.0
v1.20.10303.0
v1.19.10302.0
v1.18.10301.0
v1.20.10293.0
v1.19.10292.0
v1.18.10291.0
v1.18.3181.0
v1.19.3172.0
v1.19.2831.0
v1.18.2822.0
v1.19.2682.0
v1.18.2681.0
v1.18.1462.0
v1.17.11461.0
v1.18.1421.0
v1.17.11391.0
v1.17.11043.0
v1.16.10261.0
v1.17.1023
v1.16.10231.0
v1.15.3465.0
v1.16.3463.0
v1.15.2712.0
v1.15.2874.0
v1.16.2641.0
v1.16.2523.0
v1.15.2524.0
v1.15.2282.0
v1.14.2281.0
v1.14.1962.0
v1.15.2002.0
v1.15.2001.0
v1.15.1862.0
v1.14.1861.0
v1.14.1451.0
v1.14.1432.0
v1.13.11431.0
v1.13.10983.0
v1.12.10982.0
v1.13.10733.0
v1.12.10732.0
v1.13.10395.0
v1.12.10393.0
v1.13.10336.0
v1.12.10334.0
v1.12.3472.0
v1.11.3471.0
v1.12.2931.0
v1.12.2922.0
v1.11.2921.0
v1.11.2731.0
v1.10.2714.0
v1.11.2421.0
v1.10.2383.0
v1.10.1933.0
v1.9.1942.0
v1.9.1523.0
v1.8.1521.0
v1.9.1445.0
v1.8.1444.0
v1.8.1092.0
v1.7.1091.0
v1.8.1032.0
v1.7.1033.0
v1.7.572.0
v1.6.10571.0
v1.5.10411.0
v1.6.10412.0
v1.6.10272.0
v1.5.10271.0
v1.5.3242.0
v1.4.3243.0
v1.5.3142.0
v1.4.3141.0
v1.4.2652.0
v1.3.2651.0
v1.3.2382.0
v1.2.2381.0
v1.1.2233.0
v1.2.2234.0
v1.1.2021.0
v1.2.2022.0
v1.1.1812.0
v1.0.1811.0
v1.1.1671.0
v1.0.1401.0
v0.11.1333.0
v0.11.1251.0
v0.11.1191.0
v0.11.1111.0
v0.11.1121.0
v0.10.781.0
v0.10.761.0
v0.9.433.0
v0.8.10261.0
v0.8.10091.0
v0.7.3451.0
v0.7.3382.0
v0.7.3291.0
v0.7.3252.0
v0.6.3181.0
v0.6.2951.0
v0.6.2911.0
v0.5.2762.0
v0.5.2761.0
v0.5.2681.0
v0.5.2661.0
v0.3.2321.0
v0.4.2342.0
v0.4.2382.0
v0.3.2171.0
v0.3.2142.0
v0.2.1831.0
v0.2.1715.0
v0.2.1703.0
v0.1.1621.0
v0.1.1581.0
v0.1.1502.0
v0.1.1431.0
v0.1.1361.0
v0.1.1093.0
v0.1.1161.0
v0.1.1204.0
experiment-master
v0.1.1025.0
experiment-OutsideBuild
broken-tabstops
RS2-final
v0.1.1002.0
experiment-rel-windows-inbox
experiment-f-ServerApp
v0.1.1211.0
1904.29002
1810.02002
1708.14008
Labels
Clear labels
⛺ Reserved
A11yCO
A11yMAS
A11ySev1
A11ySev2
A11ySev3
A11yTTValidated
A11yUsable
A11yVoiceAccess
A11yWCAG
Area-Accessibility
Area-AtlasEngine
Area-AzureShell
Area-Build
Area-Build
Area-Chat
Area-CmdPal
Area-CodeHealth
Area-Commandline
Area-CookedRead
Area-DefApp
Area-Extensibility
Area-Fonts
Area-GroupPolicy
Area-i18n
Area-Input
Area-Interaction
Area-Interop
Area-Localization
Area-Output
Area-Performance
Area-Portable
Area-Quality
Area-Remoting
Area-Rendering
Area-Schema
Area-Server
Area-Settings
Area-SettingsUI
Area-ShellExtension
Area-ShellExtension
Area-ShellExtension
Area-Suggestions
Area-Suggestions
Area-TerminalConnection
Area-TerminalControl
Area-Theming
Area-UserInterface
Area-VT
Area-Windowing
Area-WPFControl
AutoMerge
Blocking-Ingestion
Culprit-Centennial
Culprit-WinUI
Disability-All
Disability-Blind
Disability-LowVision
Disability-Mobility
External-Blocked-WinUI3
Fixed
Gathering-Data
good first issue
HCL-E+D
HCL-WindowsTerminal
Help Wanted
Impact-Compatibility
Impact-Compliance
Impact-Correctness
Impact-Visual
In-PR
InclusionBacklog
InclusionBacklog-Windows TerminalWin32
InclusionCommitted-202206
Issue-Bug
Issue-Docs
Issue-Feature
Issue-Feature
Issue-Question
Issue-Samples
Issue-Scenario
Issue-Task
Needs-Attention
Needs-Author-Feedback
Needs-Bisect
Needs-Discussion
Needs-Repro
Needs-Tag-Fix
Needs-Tag-Fix
Needs-Triage
No-Recent-Activity
Priority-0
Priority-1
Priority-2
Priority-3
Product-Cmd.exe
Product-Colortool
Product-Colortool
Product-Colortool
Product-Conhost
Product-Conpty
Product-Meta
Product-Powershell
Product-Terminal
Product-WSL
pull-request
Resolution-Answered
Resolution-By-Design
Resolution-Duplicate
Resolution-External
Resolution-Fix-Available
Resolution-Fix-Committed
Resolution-No-Repro
Resolution-Won't-Fix
Severity-Blocking
Severity-Crash
Severity-DataLoss
spam
this-will-be-a-breaking-change
Tracking-External
WindowsTerminal_Win32
Work-Item
zAskModeBug
zInbox-Bug
Mirrored from GitHub Pull Request
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: starred/terminal#3747
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @DHowett-MSFT on GitHub (Sep 5, 2019).
Originally assigned to: @j4james on GitHub.
Right now, every time Renderer needs to switch the brush colors, it does the following:
TextColorfrom the attribute runEngine::UpdateDrawingBrushesStep 2 is lossy, and is the source of a class of bugs I'll call "ConPTY narrowing" bugs. In addition, there's a step where
VtEngineneeds to know the color table to do a translation from RGB back into indexed color."narrowing" bugs
\e[38;2;22;198;12m\e[92m\e[38;5;127m\e[38;2;175;0;175m\e[38;2;12;12;12m\e[30mIf Renderer passed the TextColor directly to the Engine, Xterm256Engine could pass through all indexed colors unchanged, and XtermEngine and WinTelnetEngine could flatten to the 16-color space.
@zadjii-msft commented on GitHub (Sep 5, 2019):
On a scale of 1-10, how related to #1223 is this?
I already have a fix for #1223 that involves storing 256-color attributes as an index and looking up their color when we want to render them, not when we write them.
I guess this kinda dovetails with that work nicely. Should we do this for 20H1? If so, I'll send the other PR ASAP and get on this one next.
@ExE-Boss commented on GitHub (Sep 5, 2019):
Probably quite a bit, since according to the above table,
conhostcurrently converts 256‑color attributes into 24‑bit TrueColor RGB values.@DHowett-MSFT commented on GitHub (Sep 5, 2019):
Scale: 10
@Undercat commented on GitHub (Apr 2, 2020):
I think I can solve part of the problem pretty easily. Enough to take care of issue #5201, at least.
At around line 223 in paint.cpp you have the following as part of
_RgbUpdateDrawingBrushes()(reformatted for brevity):The above code prefers 4-bit SGR over 24-bit SGR—even though it claims to be formatting truecolor output, as opposed to
_16ColorUpdateDrawingBrushes()—so you effectively assume that the PTY slave maps those 16 primary colors to the same RGB intensities that you do. This is not always going to be the case.By deleting the middle condition entirely, at least you would be generating SGR in a uniform 24-bit color space. The values sent for the 16 primary colors would, of course, still be encoded with your color table values, instead of whatever the downstream's intensity mapping for the primaries might happen to be, but at least the color space would not exhibit discontinuities related to mismatches between primary color tables.
It only solves “half” the problem, as I said, because you still don't know what SGR labeling may have initially produced the RGB intensity values in your buffer, but I think it’s a very cheap fix for what DHowett called “narrowing bugs.”
Am I missing something?
@DHowett-MSFT commented on GitHub (Apr 2, 2020):
Getting rid of the 16-color SGR will make it impossible for PTY hosts to redefine the 16-color palette entirely, as the pty driver will translate
31into, say,38;2;355;0;0. There's no way for a pty host to push its view of the palette into the pty driver.@Undercat commented on GitHub (Apr 2, 2020):
No problem. The important issue is to encode in 24 bits. The values being encoded are unimportant. Change the middle condition to...
@DHowett-MSFT commented on GitHub (Apr 2, 2020):
But that’s still going to convert an application’s request for
31into a 24-bit value and make it impossible for a connected terminal to determine that the application emitted31. It’s just flipping this issue over so that a different set of data is lost, but this time the lost data is the entire 16-color palette, isn’t it?@Undercat commented on GitHub (Apr 2, 2020):
Absolutely. Like I said, it doesn't solve the issue of recovering the initial SGR labeling used to produce the RGB intensity values from which you render output, but it will solve the issue of relying on the assumption that the slave uses the same RGB values for
\e[31mthat you do.For example, if you generate output for foreground RGB(118, 118, 118) now, with the default primary palette, your render routine for VT will generate
\e[90mwhich may not be mapped back to RGB(118, 118, 118) by the slave. They may map the palette colors differently. Practically everyone does, in fact.With my change, the renderer will produce a 24-bit SGR label and the PTR slave will not be able to change it. So at least the palette will be uniform. Right now, it is only uniform if the slave's primary color palette matches yours.
Effectively, my suggesting converts the “narrowing bug” into a “widening bug”—you still won’t be able to recover true 256-color SGR labels, for instance. You won’t ever generate
\e[38;5;243minstead of\e[38;2;118;118;118m, but at least you won’t be generating\e[90m. That is a primary color. The primary colors are mapped by various terminal emulators in a large number of different ways. Nobody can “remap” the 24-bit SGR codes, though.In other words, the situation you have now is actually the worst of all worlds. It only renders visually correct results if the slave’s primary color palettes match yours. If they don’t match, you wind up with egregious visual artifacting, as can be seen in mintty/mintty#981
@DHowett-MSFT commented on GitHub (Apr 2, 2020):
I appreciate that, but that correctness introduces a more immediate visual issue: the user’s carefully-crafted 16-color palettes are overridden because the pty driver is sending out 24-bit color. For now, I’m willing to accept “sixteen of the 16,000,000 colors are rendered incorrectly” if the immediate alternative is “all sixteen of the user’s specified colors are lost”. Just picking our trade offs 😄
@Undercat commented on GitHub (Apr 2, 2020):
Yes, that is quite true. The best solution, by far, would be able to reconstruct the original SGR labeling used by the console application to produce the color change in the first place.
In order to do that, you would have to send the SGR code down to the renderer: if the renderer happened to be a VT driver, out the door the code would go; if it were a screen painter, though, the SGR would have to be decoded on-the-spot. You would have to push the decode down to your renderers, as you originally suggested...or at least tag colors in your buffer with a “width code”, so the VT drivers would know what flavor of SGR code to generate.
A much more complicated proposition than changing a few characters, for sure! 😸
@zadjii-msft commented on GitHub (Apr 2, 2020):
I think the solution we had in mind was plumbing our
TextColororTextAttributestructures all the way to the renderer, instead of just theCOLORREF, then letting the renderer decide what it wants. Most of the render engines will just want the RGB color, but the VT render engine will actually be able to use theTextColorto differentiate between someone setting a color from the 16-color palette and someone coincidentally using the same RGB value as one of the 16-color values.@Undercat commented on GitHub (Apr 2, 2020):
Unfortunately,
TextColoralone would not be enough. Although it could certainly distinguish between 4-bit and 24-bit SGR labelings, it would have no way of recording and reconstructing 8-bit labelings.I was thinking about hiding information in the high-order octet of
COLORREF, since nobody uses it, but certain opaque downstream functions might actually insist that it be zero, likeWINAPI SetColor(). Not being able to overloadCOLORREFmeans that a fairly large number of changes would be needed to insure that all consumers, likeUpdateDrawingBrushes(), digest some new “color record,” from which they could simply extract aCOLORREF, if that's all they need.Do any of you happen to know where the input stream (ANSI SGR escape sequences, in particular) gets decoded into properties, like
COLORREFs? I've been poking around, but I don't have enough context to zero in on it with simple searches.@zadjii-msft commented on GitHub (Apr 2, 2020):
IIRC, I had a super old branch where I tried to get
TextColorto store a 256-color index, not just a 16-color index. I'm not sure that this is the right branch, but dev/migrie/b/1223-change-256-table looks like it might be the one I'm thinking of.That might be able to be combined with the "plumb
TextColorthrough" to get all of 4bit, 8bit, and 24bit colors in the same format they were originally.@DHowett-MSFT commented on GitHub (Apr 2, 2020):
Doesn't it already store a 256-color index, though? With
_meta = ColorType::IsIndexand the union's_indexvalue storing the index 0-255... we should be able to determine if it's being used for <16 and <89.Unless the issue is that the first 16 colors in the 256-color palette and the traditional 16-color palette are disjunct. If that's the case, Xterm was perhaps crazy for doing that.
@Undercat commented on GitHub (Apr 2, 2020):
I'm thinking it might actually be best to hijack
COLORREF, after all. Stripping the high octet in the screen-painting renderers is no more inconvenient, in practice, than defining a new type to convey the information to them and extracting aCOLORREFin situ.There’s just one problem remaining...I don't have enough bits in a
DWORDto unambiguously record all the information required. I can certainly minimize the loss to a trivial level that will be indistinguishable in practice, but it will not reconstruct the input stream with 100% fidelity.To wit, if you take the high octet and use it store the index value for 8-bit SGR labelings, you can get the 4-bit labelings for free. Although I am unaware of any absolute requirement to do so, virtually everyone treats the first sixteen indices of the VGA color table as duplicates of the CGA color table. This is, in fact, the default SGR behavior.
So, imagine the high octet contains a value less than 17, you would simply emit a 4-bit SGR label; if it contained a value 17 or above, you would emit an 8-bit SGR label; if it was zero, and the 24-bit color in the rest of the word matched the value for "black", you would send
\e[30m or \e[40m—if it didn’t match, you would send the 24-bit color. Not perfect, but it avoids using aUINT64to hold the one extra bit you need to disambiguate the 4-bit and 8-bit cases without resorting to reverse look-up tables for all outputs...which will be costly.Thoughts?
@Undercat commented on GitHub (Apr 2, 2020):
I cannot find any example where they are disjoint in practice.
The scheme I describe avoids disambiguating a union on the color data—the 24-bit color is always available. The extra data can just be stripped out or ignored by anyone that doesn't need it.
@egmontkob commented on GitHub (Apr 2, 2020):
The first 8 used to be different in xterm; I mean the colors were the same (i.e. a single 256-color palette, along with OSC 4 for setting it), but the legacy notation (e.g.
31) did convert it to bright counterpart when asked to be bold (1); whereas the 256-color notation (e.g.38:5:1) did not, it kept the dark color and painted that with bold typeface. VTE copied this behavior.Xterm stopped doing this in version 331 (I'm not aware of any place where
31works differently than38:5:1(which doesn't imply there isn't any)). In VTE we kept treating them differently.@zadjii-msft commented on GitHub (Apr 2, 2020):
@DHowett-MSFT It is capable of storing 8bit in the index there, but doesn't currently. This commit
608c660bfrom the aforementioned branch changes conhost to actually use the index as a 8bit value, not just a 4bit one. We're currently storing two tables, but ignoring the first 16 of the 256 color table. That's dumb, obviously, but an artifact of the organic growth of RGB color in conhost.@Undercat commented on GitHub (Apr 2, 2020):
Mmmm. Interesting.
Well, the “ideal” solution would be to push a
UINT64to the renderers that has complete color information in it, without overlap. I doubt this would cause any overflow to the stack for the relatively modest function calls involved, even on 32-bit platforms. That way, a renderer could immediately access whatever encoding it needed and only one forward look-up would need to be done to decode the color at the time the escape sequence is parsed.@zadjii-msft commented on GitHub (Apr 2, 2020):
@Undercat or perhaps 2 32bit
TextColor's? 😆@Undercat commented on GitHub (Apr 2, 2020):
@zadjii-msft lol.
You could, I suppose, push overlapped (union'd) data down and let the renderers figure out what to do with it for their own purposes. You could then unambiguously record 4-bit, 8-bit and 24-bit SGR labelings just by extending
TextColor's metadata to add the 8-bit case and have three encoding cases instead of two. You would have color index look-ups all over the place that way, but then again, who cares? It would, at least, keep the 32-bitDWORDparameter....@egmontkob commented on GitHub (Apr 2, 2020):
If this is not a problem then encoding the union of 256-color index and 16M truecolor plus some special values is trivial in 25 bits. Sounds to me like the best approach. (Also what VTE does by the way.)
Somehow I have the impression that WT devs don't like it, or it's not sufficient for WT's architecture; the resolved color (24 bits) and the origin (256 indices or direct true color = 257 or so possible different values) have to be carried together. And for this you would need just a tiny little more than 32 bits.
If indeed the resolved RGB and the origin of the color needs to be both carried, and squeezed into 32 bits, there are still some tricks to consider.
One idea is to drop the color precision of the R and/or B channel to 7 bits. No one will notice with their bare eyes, only when using some color picker software to check the exact color.
Another idea is not to allow to alter the extra 240 colors, only the basic 16 ones. (All terminals I've checked have the exact same default RGB for these 240 additional entries.) For the additional ones, the RGB value wouldn't be directly stored, but could be derived using a fixed hardwired table.
But you can also relax on this limitation: allow the extra 240 colors to be freely modified, with just one limitation: the last 24 entries (the grayscale ones) must be grayscale. With this limitation all the information can be squeezed into 32 bits. E.g. the high 8 bits are either the index (0..231) or maybe 232 for "default", 233 for "grayscale", in the latter case you have 24 more bits to store the actual grayscale index (4 bits), plus the R=G=B component (8 bits) and still have 12 bits free... which you could use to further loosen the restriction, and allow almost-grayscale colors, where the color components aren't too far away from each other :-)
@Undercat commented on GitHub (Apr 2, 2020):
@egmontkob That was rather like what I was thinking about originally. There appears to be one additional difficulty, however. There is an extra flag in
TextColorused for “default color.”Really, as long as you’re okay with multiplexing color information (by creating unions that have to be decoded by the consumers), you can directly encode the 4-bit, 8-bit and 24-bit cases and then reconstruct the original SGR input for VT sinks with 100% fidelity.
I'm doodling a test case right now by creating a class (really just a structure with methods) that has assignment overloads for
WORDandDWORDthat automatically reconstruct the 4-bit legacy attribute color or 24-bitCOLORREFdata from a union...with a gaggle of methods to write SGR4|8|24 color sequences from the same data. This would minimize changes to the consumers of color data—basically, you would just have to change the color parameter’s formal type fromCOLORREFto something likeColor.Since the new type would behave like a
COLORREFin most situations, fewer changes would need to be made to all the hungry consumers of color data, hopefully making this parameter enhancement (to support differentiable SGR labelings) less apocalyptic, in terms of code-change footprint.@Undercat commented on GitHub (Apr 3, 2020):
Well, this is a skeleton of what I propose morphing
TextColorinto (I prototyped it in GNU using a much more compact style because it's more comfortable for me to design and test things that way, but just imagine it expanded out into Microsoft syntax for the moment).Basically:
COLORREFfor easy interconversion (simple masking).It would be necessary to re-plumb
TerminalApi.cppandTerminalDispatchGraphics.cppin order to record the source type accurately enough (right now, there is a complete reliance on constructor type overloading in order to determine the color regime used by the source, but that is inappropriate and dangerous when you start getting multiple types that are built on single octet data words, in addition to being confusing...better to make it explicit).Before I even start to shoe-horn this monster into the existing code (which will obviously take more than a day, not including validation), I'd be interested in some feedback. Comments? Suggestions? Flames?
@j4james commented on GitHub (Apr 21, 2020):
@Undercat Personally, I'd recommend leaving the
TextColorclass alone. Fixing this issue requires changes to a number of areas of the code base, including the renderer, the SGR dispatcher, and color table management (I'm working on some of these things at the moment). TheTextColorclass is the least of the problems, and rewriting that now is just going to cause a lot of pain without actually fixing anything. At most I think it might need an additionalColorTypeoption.@zadjii-msft commented on GitHub (Apr 24, 2020):
Holy crap I had this whole big long message typed up and I never sent it to this thread D: That's my bad. Lemme think if I can try and recover some of my thoughts here
Woah, thanks for the contribution here. There's certainly a lot to look at, so I might be reading some of the details wrong here.
I'm still not sure how this is better than TextColor+"change
_indexto be a 8bit index, instead of just a 4bit one". I'm not sure there's a lot of value in tracking 4bit VT indices separately from legacy ones - since legacy colors were always a 4bit index, we're trying to treat them as effectively the same thing as a VT 4bit index.There unfortunately is - because the Win32 console API provides a mechanism for reading back the contents of the buffer, including text attributes, but only as legacy attributes, we need to be able to convert the non-legacy attrs back into legacy ones.
I'm not sure that
Color::asRGBis going to be called in any fewer places thanTextColor::GetColoralready isThis is nice, and I’d be interested to see if it could be integrated with
TextColorrather than replace it entirelySorry again to ghost this thread accidentally 😬
@Undercat commented on GitHub (Apr 25, 2020):
I changed the "class" name to
Coloronly to make debugging easier. Changing the name would cause all consumers of color data to fail catastrophically whenTextColorgets deleted, insuring that all downstream dependencies would be found and updated to conform to the new, extended, API.This would prevent subtle bugs from being masked by incomplete functional similarities between the old and new color representations, but in the abstract, it really doesn't matter what you call the class/structure—the feature extension that I consider to be sine qua non is adding explicit support for distinguishing 4- and 8-bit SGR labelings from legacy 4-bit color and truecolor.
I distinguish legacy 4-bit color from 4-bit SGR color to avoid very subtle, and fortunately also very obscure, color bugs.
Different screen writers can have different expectations about what color mapping is used for 4-bit color, and
TextColoris unable to satisfy both those expectations at the same time. It cannot distinguish between text that is written using the Windows API and text that should be passed-through using SGR. Most of the time, this will not cause a problem, and for those situations where it is a problem, there frankly is no good fix. Converting the Windows 4-bit legacy color values to 24-bit color values would eliminate any color infidelities caused by mismatched color tables, but it assumes that the downstream renderer is 24-bit capable. Still, I'd rather have the option of making the distinction than not having that option...and later needing it. Just my bias.Of course, this does not seem to be an issue for 8-bit SGR because, as near as I can tell, the Windows console has never supported 8-bit native color. Besides, the upper part of the VGA color table is almost never changed from its canonical values, so it's likely to have the same values everywhere.
Now, as far as color tables are concerned: the new structure does not care how color mappings are represented—such mappings are an altogether different branch of code I haven't dealt with here at all, except as a dependency. The only thing
Colorattempts to do is encapsulate the color transformations in one place, but you could just as easily generate SGR externally from 4/8/24-bit values and an index key.Leaving
TextColorlargely intact would be difficult, but then, in all fairness, shoe-horning a new representation in to replace it would be non-trivial, too.To minimize changes to
TextColor, you'd basically have to modify the input state machine to explicitly record 4- and 8-bit SGR codes; extendTextColorto support those codes in some way, at least by eliminatingTextColor's existing dependence on constructor overloading to implicitly differentiate between 4-bit and 24-bit color values (which presently is the only way of initializing color data); then extend the existing color mapping system to provide support for 8-bit color indices, in addition to the 4-bit indices; and finally, modify the SGR output routines (inVtEngine) to explicitly reconstruct 4-bit and 8-bit SGR codes, when appropriate, for VTs.And, of course, you can then also change whatever readback function @zadjii-msft referred to, above, to reconstruct values from the new color representations (4-bit and 8-bit SGR values). The goal is essentially to avoid using truecolor as a "universal" intermediate for extended colors...a use which presently makes it impossible to regenerate SGR codes with fidelity, and is what got me started on this whole thing in the first place.
I really would try hard to encapsulate all these color representations to avoid leaking different color encodings all over the place, even if it requires separating the SGR parser/generator for colors values from the rest of the SGR parser/renderer. That's just my personal paranoia, though.
Somehow, I managed to spent over an hour looking again for the exact code that parses the CSIs out of the input stream...to no avail. Should have bookmarked it, I suppose, but I didn't think this was going anywhere, since I got no feedback for weeks.... Anyway, I really don't have the time to spend on this right now—especially given the high potential for long and painful iterations raised by the highly-non-local nature of the changes required, and the fact that @j4james is already modifying some of the code involved. The fact that I don't actually have a personal use-case for any of the code involved doesn't help.
Still, I did just outline (in very broad strokes) some of the changes that I feel would be required to support SGR color with any fidelity. Some of you Microsoft natives can probably agree amongst yourselves on how to make the required changes in the course of your other work that already touches upon the relevant code. That would probably be 10x easier than having me attempt to make such changes in relative isolation.
Sorry I couldn't be of more help.
Cheers!
@DHowett-MSFT commented on GitHub (Apr 25, 2020):
@undercat (sorry again for the delay, and we absolutely appreciate your input on this -- it's one of the ways we're hoping to be "better together" 😄)
@j4james commented on GitHub (Apr 25, 2020):
Just to clarify my position, I'm working on some areas of the code that relate to this issue (like the SGR dispatcher), and as part of that I've been experimenting with a partial fix for this issue as well. But that's mostly been to validate the changes I'm making to the API. Fixing this issue is not the focus of my work at the moment, so I don't want to discourage anyone else from taking it on in the meantime (although I think that'll be tricky without other fixes being in place first).
The main point of my previous comment, though, was that I didn't think a
TextColorrewrite was necessary, and would entail a lot of work with no real benefit. I don't think there's any value in trying to preserve the exact format of every SGR sequence in the screen buffer, because realistically that's never going to be a perfect representation. And in the long term, clients that need that level of fidelity will be using something like the pass-through mode anyway.So if we stick to what is actually needed to generate the correct output, rather than trying to reproduce the original input, I think there are only four color types we need to worry about.
I would probably expect colors set via the console APIs (e.g.
SetConsoleTextAttribute) to map to case 3. They're indexed colors, which should be affected by the color table, but they probably shouldn't be brightened by SGR 1.So as I see it, the only thing missing from the existing
TextColorimplementation is the ability to distinguish been cases 2 and 3. And for that, all we really need is one moreColorType, and maybe something on the index constructor designating which index variant is being set.@Undercat commented on GitHub (Apr 25, 2020):
You absolutely need to store information about the original SGR labeling that led to a color being in the buffer. I cannot emphasize this enough: if you do not know the labeling that produced a color value in the buffer, you cannot guarantee its correct reproduction.
@j4james you need to remember that the terminal "wrapper" may have a different view of the indexed colors than any downstream VT used to actually render the output. They each can have different color tables. When they do, if you continue to generate SGR codes based on the actual color value in your buffer, without knowing what SGR labeling produced it, you have no way of distinguishing between labelings that map to the same color in terminal, but different colors on the VT.
You wind up with a non-invertible many-to-one mapping in terminal that forces you to arbitrarily choose an SGR code to output. Right now, it chooses the shortest possible SGR code. That produces the visual error in mintty/mintty#981 and is why I ran down this rabbit hole to begin with.
You cannot fix this problem without extending
TextColorto distinguish the original SGR code that produced a color in the buffer. It's not as simple as differentiating colors based on how other attributes, like brightening, might apply to them.@j4james commented on GitHub (Apr 25, 2020):
We definitely won't be generating the SGR codes based on the RGB value if that's what you mean. As I said above, the are four different color types I think we need to retain, and we would generate VT sequences that best represent those types. I just don't think we need to differentiate between something like SGR 95 and SGR 38:5:13 if they're going to produce the exact same color on every terminal. Mintty certainly doesn't seem to interpret them differently.
It would help if you could provide an example of a specific color sequence that you think we'd be getting wrong without the additional types you're proposing, and also what terminal you'd expect it to fail on.
@egmontkob commented on GitHub (Apr 25, 2020):
Are you sure that you won't ever need it, and that they look exactly the same on every terminal?
For the second eight colors (SGR 90 .. 97 vs. 38:5:8 .. 38:5:15, and the same with hundreds and forties for background) this might easily be correct, probably it is correct, although I'm not 100% sure. And no one can guarantee that xterm or some other popular terminal will never introduce some difference, e.g. SGR 2 faint getting applied to the first format only.
For the first eight colors (SGR 30 .. 37 vs. 38:5:0 .. 38:5:7, and the same with forties for the background) you know it's not true, we've just recently talked about it in #5384. Unless you want to hardcode the xterm 331 .. 347 behavior forever.
Which means you can perhaps squash the two representation of the second 8 colors, but not the first 8. Where does it take you? A more complex, harder to understand and harder to maintain codebase, with some squeezing logic where it's not required at all. Different codepath for the two possible representations of the first 8 colors versus the two possible representations of the second 8 colors, not just where they need to differ, but elsewhere too. Harder to debug, as you'll run into unexpected inconsistencies wherever you peek into the data. Saving 8 possible values out of the little-bit-more-than-2^24 values, still resulting in little-bit-more-than-2^24, that is, not solving anything here. And in some presumably very rare cases, where the two representations of the same color reside next to each other, you might save a few bytes getting transferred. I find it absolutely pointless.
The experience of having already fixed quite a few color handling bugs in VTE tells me that @Undercat is on the right track here. Treat 95 and 38:5:13 differently all the way through, it's pointless to "optimize" solely for the sake of 8 colors, based on the current knowledge / future assumption that they'll end up being the same RGB. Such "optimization" is counterproductive, you lose a lot by having more complex architecture and more complex code, while practically win nothing.
IMO squeezing them only made sense if the two different notations of the 16 colors would be synonyms, and would be guaranteed that they'll always remain so (as in, let's say, it's okay to forget whether it was
38:5:13with colons, or38;5;13with semicolons). This is clearly not the case here.@j4james commented on GitHub (Apr 25, 2020):
Sure enough that I'm not going to encourage a whole lot of unnecessary changes to the code base on the off chance that it might be an issue 10 years from now on some obscure terminal that nobody has heard of. However, if you can come up with a genuine use case that is going to impact users in a meaningful way, please do let me know.
Which is why I'm not suggesting we treat SGR 30 the same as 38:5:0. See my message above. I proposed two index types to distinguish between these two cases. SGR 30 is case 2 (indexed colors that can be brightened), and SGR 38:5:0 would be case 3 (indexed colors that shouldn't be brightened).
Anyway, I can't stress enough how little any of this matters. The difficult part of getting this issue fixed is in places like the dispatcher and the renderers, and then figuring out all the little issues that are going to break once the existing behaviour changes. Adding more color types in the future, if we really need to, is trivial in comparison.
@DHowett-MSFT commented on GitHub (Apr 25, 2020):
Right- regardless of which particular representation we use and its fidelity, the first step towards closing #2661 is us having a framework for piping attributes around instead of just RGB color values. Once we nail that, we can work on improving the fidelity wherever it is practical.
@egmontkob commented on GitHub (Apr 25, 2020):
@j4james I admit I slipped through some of the details in your earlier posts, apologies for that. Indeed if you're certain that the status quo won't change, the solution you're proposing is technically correct.
I'm still not a great fan of it architecturally, since some of the decisions (within case 3 mapping 90..97 into the same slots as 38:5:8..15) happen before the colors are stored wherever they are stored (and you lose info that might be useful for debugging etc.) and some other decisions (e.g. whether to actually brighten case 2) when it comes to hitting the screen pixels; that is, the whole logic is split into two vastly different places – whereas all of these could be done at this latter step, which I'd find a much cleaner, simpler architecture.
Anyway, as you say, it indeed really doesn't matter.
@Undercat commented on GitHub (Apr 25, 2020):
They absolutely are not guaranteed to be the same color intensity values on every terminal. They will only be the same color if terminal's internal color table for the primary colors + intensity (i.e., the first 16 colors in 4-bit and 8-bit color) exactly matches the corresponding color table of the VT renderer, whatever it may be.
You need to tag the source of the color so you can follow it all the way through terminal—at least given the way you convert all colors (and every other text property, for that matter) to a non-portable "common ground" internal format right now, and then render everything from that internal format. If you do not tag the origin of the colors, you will be unable to distinguish between
\e[90mand\e[38;5;8mand\e[38;5;243mand\e[38;2;118;118;118mbecause they will all have the same color value in the default Microsoft mapping.If you distinguish only based on whether a color can be brightened, you separate the first two cases. You do nothing to distinguish them from the last two cases, which should be absolute colors, but in your scheme will wind up being rendered as Microsoft default colors.
Classifying the colors based on the ancillary properties that might apply to them is insufficient. You need enough information to distinguish between the four alternatives I just listed, and the only approach that guarantees a given SGR input stream will produce the same SGR output stream is to tag the colors by their origin.
Now, you could get around this problem by only generating 24-bit SGR colors, but this assumes that the VT renders truecolor (likely) and it also eliminates emitting primary SGR codes (30/90 series) entirely. If you restrict the 24-bit up-conversion to VT SGR renderings only, then all will be well from a color fidelity standpoint...assuming the downstream renderer can handle 24-bit SGR codes. But you will never be able to generate a primary SGR color this way, and since those are the colors that everyone remaps, you will effectively be forcing all renderers to use terminal's colormap.
I already had that discussion with @zadjii-msft a long time ago, but I don't think the implications are being appreciated here.
@DHowett-MSFT commented on GitHub (Apr 25, 2020):
@Undercat given that this entire workitem was filed to capture "stop converting all colors into their 24-bit RGB representations and therefore losing fidelity", I think that most of your concerns are already noted.
What we have, today:
This is incorrect. This is what this issue seeks to solve.
What we have, with this issue closed:
What we can have in the future, with the architecture this issue lays down:
All that to say:
When this issue is closed, there will be no dependency on the console host's internal color table and no assumption that a connected terminal will share the same color table.
@Undercat commented on GitHub (Apr 25, 2020):
I can't seem to get through, unfortunately. You have absolutely no way of knowing if a color you output is "close" to its "input value." You don't know what the input color is; you only know what SGR encoding the application asked for.
You convert that SGR code using your internal color tables. Those color tables may not match what is used by an external renderer.
Specifically, if the renderer thinks that
\e[90misrgb(85,85,85)and you putrgb(118,118,118)into the buffer because that's what you think\e[90m's color should be, according to your internal color table, you have already irretrievably lost information that will foreverafter prevent you from recovering and reproducing the VT's notion of what that color should be.On output, you will generate an SGR value that corresponds "closely" to
rgb(118, 118, 118)because "that's what's in the buffer," but its not what the SGR color you received was calling for.If you do not make the architectural change, you will either do it later or you will ever-after force users to choose their primary palettes to be "close enough" to the Microsoft palette not to introduce visual artifacts.
@DHowett-MSFT commented on GitHub (Apr 26, 2020):
I think we are both talking past eachother.
What I mean to say is “this issue, #2661, represents the work required to make sure we can forward the SGR values without using the color as an intermediary.”
I really do mean this. When 2661 is closed, there will be no dependency on the color values in the console host’s color table.
I’d like some feedback about how I can communicate that point more effectively 😄
@Undercat commented on GitHub (Apr 26, 2020):
Oh, I see. The operative notion here is "when the issue is closed", not "when the modifications thus far suggested have been implemented."
My bad. It certainly isn't a pressing issue for me, or anything. I just wanted to make sure you understood that attaching non-SGR-specific attributes to the buffer wasn't going to fix the underlying problem.
Cheers!
@DHowett-MSFT commented on GitHub (Apr 26, 2020):
(The reason I say “as close to input as possible” is that
\e[4m\e[4mwould likely be “optimized” to, you know, not be repeated. Same with something like “4;24” or anything that overrides or contradicts itself or stuff like that.)@Undercat commented on GitHub (Apr 26, 2020):
Gotcha. Visually-idempotent transformations: no problem. 😸
@j4james commented on GitHub (Jun 13, 2020):
I've been working around the edges of this issue for a while now, but I've got to the point where I'd like to try and finish off my POC and turn it into a PR. Does anyone have any objections to me doing that? Technically this issue is still assigned to @zadjii-msft so I don't want step on any toes.
Also, any suggestions for testing the 16-color xterm and telnet engines? So far I've just been patching the conhost command line in winconpty.cpp to startup with a different mode, but is there a better way? In the case of telnet, it would be nice to test via the telnet client itself if that were possible.
@DHowett commented on GitHub (Jun 13, 2020):
@j4james you’re more than welcome to. I view my assignments as some hybrid between “would be the person on my team tasked with doing the work eventually” and “is the subject matter expert, and can answer community questions for the implementor.” In this case, I think you might be the current subject matter expert 😉 so conversely, is it okay if I assign you?
The “best” way to test those engines right now is, unfortunately, exactly what you’re doing. If you’d like to test with the telnet engine and the actual telnet client, it’ll be a bit difficult because the telnet server no longer ships with desktop Windows ... hm.
Our coverage story for these engines is very, very shaky. I don’t even know of a use of the non-24bit color xterm engine anywhere in Windows.
If you replace your system’s
conhost.exewith OpenConsole (no warranty!) running Windows executables through WSL will launch ConPTY, but even that just uses the Xterm256Engine.There might be something fun to be done with VTPipeTerm?
@j4james commented on GitHub (Jun 13, 2020):
This part of the code was actually a little outside my comfort zone to start with, but I'm far enough along now that I'm reasonably confident I can get it done, so you're welcome to assign to me. With any luck I should have something ready this weekend. Although I should point out that we'll probably still need to address #5952 before we'll want to merge these fixes.
Yeah, I was wondering about that too.
OK. I might try that with a patched version of OpenConsole with one of the other engines hard coded.
I did briefly try that, but couldn't get it to work. It kept randomly dropping escape characters (or something to that effect) so half the VT sequences would get printed to the screen instead of being interpreted.
@zadjii-msft commented on GitHub (Jun 15, 2020):
(just for more info - the inbox
telnetdthat we ship internally actually usesxterm-ascii, not theWinTelnetEngine. After building the WinTelnetEngine, I discovered that the inboxtelnetwas capable enough of doing everything the xterm engine was doing, aside from 256 color and utf-8 character encoding. We probably should just delete it at some point.)@ghost commented on GitHub (Jul 22, 2020):
:tada:This issue was addressed in #6506, which has now been successfully released as
Windows Terminal Preview v1.2.2022.0.🎉Handy links: