-- Plan9 colorscheme for Neovim -- Authentic Plan 9 / Acme colors from plan9port and 9front source -- All colors derived from libdraw constants and acme/rio/sam source code -- Syntax highlighting uses only the Plan 9 system palette local M = {} -- Authentic Plan 9 palette (from draw.h / libdraw) local p9 = { black = "#000000", -- DBlack white = "#ffffff", -- DWhite red = "#ff0000", -- DRed green = "#00ff00", -- DGreen blue = "#0000ff", -- DBlue cyan = "#00ffff", -- DCyan magenta = "#ff00ff", -- DMagenta yellow = "#ffff00", -- DYellow paleyellow = "#ffffaa", -- DPaleyellow darkyellow = "#eeee9e", -- DDarkyellow darkgreen = "#448844", -- DDarkgreen palegreen = "#aaffaa", -- DPalegreen medgreen = "#88cc88", -- DMedgreen darkblue = "#000055", -- DDarkblue palebluegreen = "#aaffff", -- DPalebluegreen paleblue = "#0000bb", -- DPaleblue bluegreen = "#008888", -- DBluegreen greygreen = "#55aaaa", -- DGreygreen palegreygreen = "#9eeeee", -- DPalegreygreen yellowgreen = "#99994c", -- DYellowgreen medblue = "#000099", -- DMedblue greyblue = "#005dbb", -- DGreyblue palegreyblue = "#4993dd", -- DPalegreyblue purpleblue = "#8888cc", -- DPurpleblue -- Acme computed mixes (allocimagemix) acme_body = "#ffffea", -- DPaleyellow + DWhite mix (acme text bg) acme_tag = "#eaffff", -- DPalebluegreen + DWhite mix (acme tag bg) -- Acme UI specific b2_red = "#aa0000", -- Mouse button 2 (execute) b3_green = "#006600", -- Mouse button 3 (look/plumb) scroll = "#444444", -- Sam scroll indicator pale_text = "#666666", -- Rio inactive text rio_bg = "#777777", -- Rio desktop rio_inactive = "#999999", -- Rio inactive border } local colors = { -- Editor base (Acme body) bg = p9.acme_body, bg_dim = p9.darkyellow, bg_dark = p9.yellowgreen, fg = p9.black, fg_dim = p9.pale_text, fg_faint = p9.rio_inactive, -- Acme tag bar tagbar = p9.acme_tag, tag_sel = p9.palegreygreen, tag_border = p9.purpleblue, -- Selection (Acme body selection) selection = p9.darkyellow, cursor_line = "#f5f5d5", -- Borders border = p9.yellowgreen, -- Syntax (using only Plan 9 system colors) comment = p9.yellowgreen, string = p9.b2_red, keyword = p9.medblue, func = p9.bluegreen, type = p9.darkgreen, const = p9.darkblue, preproc = p9.greyblue, special = p9.purpleblue, operator = p9.scroll, -- Diagnostics / semantic (Plan 9 UI colors) error = p9.b2_red, warn = p9.yellowgreen, info = p9.darkgreen, hint = p9.bluegreen, -- Git (semantic using Plan 9 palette) git_add = p9.darkgreen, git_change = p9.yellowgreen, git_delete = p9.b2_red, -- Diff backgrounds (pale versions) diff_add = p9.palegreen, diff_delete = "#ffaaaa", diff_change = p9.darkyellow, diff_text = p9.yellowgreen, -- Line numbers line_nr = p9.rio_inactive, -- Modified indicator modified = p9.medblue, } function M.setup() vim.cmd("hi clear") if vim.fn.exists("syntax_on") then vim.cmd("syntax reset") end vim.o.background = "light" vim.g.colors_name = "plan9" local hi = function(group, opts) vim.api.nvim_set_hl(0, group, opts) end -- Editor hi("Normal", { fg = colors.fg, bg = colors.bg }) hi("NormalFloat", { fg = colors.fg, bg = p9.acme_tag }) hi("FloatBorder", { fg = colors.tag_border, bg = p9.acme_tag }) hi("Cursor", { fg = colors.bg, bg = colors.fg }) hi("CursorLine", { bg = colors.cursor_line }) hi("CursorLineNr", { fg = colors.fg, bg = colors.cursor_line, bold = true }) hi("CursorColumn", { bg = colors.cursor_line }) hi("LineNr", { fg = colors.line_nr }) hi("SignColumn", { bg = colors.bg }) hi("ColorColumn", { bg = colors.bg_dim }) hi("VertSplit", { fg = colors.border }) hi("WinSeparator", { fg = colors.border }) hi("Folded", { fg = colors.fg_dim, bg = colors.bg_dim }) hi("FoldColumn", { fg = colors.line_nr, bg = colors.bg }) hi("NonText", { fg = colors.border }) hi("SpecialKey", { fg = colors.border }) hi("EndOfBuffer", { fg = colors.bg_dim }) hi("MatchParen", { fg = colors.fg, bg = p9.palegreygreen, bold = true }) hi("Directory", { fg = colors.func, bold = true }) hi("Title", { fg = colors.keyword, bold = true }) hi("Conceal", { fg = colors.fg_dim }) -- Selection hi("Visual", { bg = colors.selection }) hi("VisualNOS", { bg = colors.selection }) -- Search hi("Search", { fg = colors.fg, bg = colors.selection }) hi("IncSearch", { fg = p9.white, bg = colors.keyword }) hi("CurSearch", { fg = p9.white, bg = colors.keyword }) -- Spell hi("SpellBad", { undercurl = true, sp = colors.error }) hi("SpellCap", { undercurl = true, sp = colors.info }) hi("SpellRare", { undercurl = true, sp = colors.hint }) hi("SpellLocal", { undercurl = true, sp = colors.warn }) -- Statusline (Acme tag bar style) hi("StatusLine", { fg = colors.fg, bg = colors.tagbar, bold = true }) hi("StatusLineNC", { fg = colors.fg_dim, bg = colors.tagbar }) hi("TabLine", { fg = colors.fg_dim, bg = colors.tagbar }) hi("TabLineFill", { bg = colors.tagbar }) hi("TabLineSel", { fg = colors.fg, bg = colors.bg, bold = true }) hi("WinBar", { fg = colors.fg, bg = colors.bg }) hi("WinBarNC", { fg = colors.fg_dim, bg = colors.bg_dim }) -- Popup menu (Acme tag bar colors) hi("Pmenu", { fg = colors.fg, bg = colors.tagbar }) hi("PmenuSel", { fg = colors.fg, bg = colors.tag_sel, bold = true }) hi("PmenuSbar", { bg = colors.tagbar }) hi("PmenuThumb", { bg = colors.tag_border }) -- Messages hi("ErrorMsg", { fg = colors.error, bold = true }) hi("WarningMsg", { fg = colors.warn, bold = true }) hi("ModeMsg", { fg = colors.fg, bold = true }) hi("MoreMsg", { fg = colors.info, bold = true }) hi("Question", { fg = colors.info }) -- Diagnostics hi("DiagnosticError", { fg = colors.error }) hi("DiagnosticWarn", { fg = colors.warn }) hi("DiagnosticInfo", { fg = colors.info }) hi("DiagnosticHint", { fg = colors.hint }) hi("DiagnosticUnderlineError", { undercurl = true, sp = colors.error }) hi("DiagnosticUnderlineWarn", { undercurl = true, sp = colors.warn }) hi("DiagnosticUnderlineInfo", { undercurl = true, sp = colors.info }) hi("DiagnosticUnderlineHint", { undercurl = true, sp = colors.hint }) -- Diff hi("DiffAdd", { bg = colors.diff_add }) hi("DiffDelete", { bg = colors.diff_delete }) hi("DiffChange", { bg = colors.diff_change }) hi("DiffText", { bg = colors.diff_text }) -- Syntax (Plan 9 palette — muted, deliberate color choices) hi("Comment", { fg = colors.comment, italic = true }) hi("Constant", { fg = colors.const }) hi("String", { fg = colors.string }) hi("Character", { fg = colors.string }) hi("Number", { fg = colors.const }) hi("Boolean", { fg = colors.const }) hi("Float", { fg = colors.const }) hi("Identifier", { fg = colors.fg }) hi("Function", { fg = colors.func }) hi("Statement", { fg = colors.keyword }) hi("Conditional", { fg = colors.keyword }) hi("Repeat", { fg = colors.keyword }) hi("Label", { fg = colors.keyword }) hi("Operator", { fg = colors.operator }) hi("Keyword", { fg = colors.keyword, bold = true }) hi("Exception", { fg = colors.error }) hi("PreProc", { fg = colors.preproc }) hi("Include", { fg = colors.preproc }) hi("Define", { fg = colors.preproc }) hi("Macro", { fg = colors.preproc }) hi("PreCondit", { fg = colors.preproc }) hi("Type", { fg = colors.type }) hi("StorageClass", { fg = colors.type }) hi("Structure", { fg = colors.type }) hi("Typedef", { fg = colors.type }) hi("Special", { fg = colors.special }) hi("SpecialChar", { fg = colors.special }) hi("Tag", { fg = colors.func }) hi("Delimiter", { fg = colors.operator }) hi("SpecialComment", { fg = colors.comment, bold = true }) hi("Debug", { fg = colors.error }) hi("Underlined", { fg = colors.preproc, underline = true }) hi("Ignore", { fg = colors.fg_faint }) hi("Error", { fg = p9.white, bg = colors.error, bold = true }) hi("Todo", { fg = colors.bg, bg = colors.modified, bold = true }) -- Treesitter hi("@variable", { fg = colors.fg }) hi("@variable.builtin", { fg = colors.special }) hi("@variable.parameter", { fg = colors.fg }) hi("@variable.member", { fg = colors.fg }) hi("@constant", { fg = colors.const }) hi("@constant.builtin", { fg = colors.const, bold = true }) hi("@module", { fg = colors.type }) hi("@label", { fg = colors.keyword }) hi("@string", { fg = colors.string }) hi("@string.documentation", { fg = colors.comment }) hi("@string.escape", { fg = colors.special }) hi("@string.special", { fg = colors.special }) hi("@character", { fg = colors.string }) hi("@number", { fg = colors.const }) hi("@boolean", { fg = colors.const, bold = true }) hi("@float", { fg = colors.const }) hi("@function", { fg = colors.func }) hi("@function.builtin", { fg = colors.func }) hi("@function.call", { fg = colors.func }) hi("@function.macro", { fg = colors.preproc }) hi("@method", { fg = colors.func }) hi("@method.call", { fg = colors.func }) hi("@constructor", { fg = colors.type }) hi("@parameter", { fg = colors.fg }) hi("@keyword", { fg = colors.keyword, bold = true }) hi("@keyword.function", { fg = colors.keyword, bold = true }) hi("@keyword.operator", { fg = colors.keyword }) hi("@keyword.return", { fg = colors.keyword, bold = true }) hi("@conditional", { fg = colors.keyword }) hi("@repeat", { fg = colors.keyword }) hi("@exception", { fg = colors.error }) hi("@include", { fg = colors.preproc }) hi("@type", { fg = colors.type }) hi("@type.builtin", { fg = colors.type }) hi("@type.qualifier", { fg = colors.keyword }) hi("@type.definition", { fg = colors.type }) hi("@storageclass", { fg = colors.keyword }) hi("@attribute", { fg = colors.preproc }) hi("@field", { fg = colors.fg }) hi("@property", { fg = colors.fg }) hi("@punctuation.bracket", { fg = colors.operator }) hi("@punctuation.delimiter", { fg = colors.operator }) hi("@punctuation.special", { fg = colors.special }) hi("@comment", { fg = colors.comment, italic = true }) hi("@tag", { fg = colors.func }) hi("@tag.attribute", { fg = colors.type }) hi("@tag.delimiter", { fg = colors.operator }) hi("@text", { fg = colors.fg }) hi("@text.strong", { bold = true }) hi("@text.emphasis", { italic = true }) hi("@text.underline", { underline = true }) hi("@text.strike", { strikethrough = true }) hi("@text.title", { fg = colors.keyword, bold = true }) hi("@text.literal", { fg = colors.string }) hi("@text.uri", { fg = colors.preproc, underline = true }) hi("@text.todo", { fg = colors.bg, bg = colors.modified, bold = true }) hi("@text.note", { fg = colors.bg, bg = colors.info, bold = true }) hi("@text.warning", { fg = colors.bg, bg = colors.warn, bold = true }) hi("@text.danger", { fg = p9.white, bg = colors.error, bold = true }) -- LSP hi("LspReferenceText", { bg = colors.selection }) hi("LspReferenceRead", { bg = colors.selection }) hi("LspReferenceWrite", { bg = colors.selection }) hi("LspSignatureActiveParameter", { fg = colors.keyword, bold = true }) -- Git signs hi("GitSignsAdd", { fg = colors.git_add }) hi("GitSignsChange", { fg = colors.git_change }) hi("GitSignsDelete", { fg = colors.git_delete }) hi("GitSignsCurrentLineBlame", { fg = colors.fg_faint, italic = true }) -- Telescope / Snacks picker hi("TelescopeBorder", { fg = colors.tag_border }) hi("TelescopePromptBorder", { fg = colors.tag_border }) hi("TelescopeResultsBorder", { fg = colors.tag_border }) hi("TelescopePreviewBorder", { fg = colors.tag_border }) hi("TelescopeSelection", { bg = colors.selection }) hi("TelescopeSelectionCaret", { fg = colors.keyword, bg = colors.selection }) hi("TelescopeMatching", { fg = colors.string, bold = true }) -- NeoTree (sidebar like Acme tag column) hi("NeoTreeNormal", { fg = colors.fg, bg = colors.tagbar }) hi("NeoTreeNormalNC", { fg = colors.fg, bg = colors.tagbar }) hi("NeoTreeDirectoryName", { fg = colors.fg, bold = true }) hi("NeoTreeDirectoryIcon", { fg = colors.func }) hi("NeoTreeRootName", { fg = colors.fg, bold = true }) hi("NeoTreeFileName", { fg = colors.fg }) hi("NeoTreeGitAdded", { fg = colors.git_add }) hi("NeoTreeGitModified", { fg = colors.git_change }) hi("NeoTreeGitDeleted", { fg = colors.git_delete }) -- Which-key hi("WhichKey", { fg = colors.keyword, bold = true }) hi("WhichKeyGroup", { fg = colors.func }) hi("WhichKeyDesc", { fg = colors.fg }) hi("WhichKeySeparator", { fg = colors.fg_faint }) hi("WhichKeyFloat", { bg = colors.tagbar }) -- Indent blankline hi("IndentBlanklineChar", { fg = colors.bg_dim }) hi("IndentBlanklineContextChar", { fg = colors.border }) hi("IblIndent", { fg = colors.bg_dim }) hi("IblScope", { fg = colors.border }) -- Notify hi("NotifyERRORBorder", { fg = colors.error }) hi("NotifyWARNBorder", { fg = colors.warn }) hi("NotifyINFOBorder", { fg = colors.info }) hi("NotifyDEBUGBorder", { fg = colors.fg_faint }) hi("NotifyTRACEBorder", { fg = colors.hint }) hi("NotifyERRORIcon", { fg = colors.error }) hi("NotifyWARNIcon", { fg = colors.warn }) hi("NotifyINFOIcon", { fg = colors.info }) hi("NotifyDEBUGIcon", { fg = colors.fg_faint }) hi("NotifyTRACEIcon", { fg = colors.hint }) hi("NotifyERRORTitle", { fg = colors.error }) hi("NotifyWARNTitle", { fg = colors.warn }) hi("NotifyINFOTitle", { fg = colors.info }) hi("NotifyDEBUGTitle", { fg = colors.fg_faint }) hi("NotifyTRACETitle", { fg = colors.hint }) -- Snacks (LazyVim notifications/dashboard) hi("SnacksNotifierBorderError", { fg = colors.error }) hi("SnacksNotifierBorderWarn", { fg = colors.warn }) hi("SnacksNotifierBorderInfo", { fg = colors.info }) hi("SnacksNotifierBorderDebug", { fg = colors.fg_faint }) hi("SnacksNotifierBorderTrace", { fg = colors.hint }) hi("SnacksDashboardHeader", { fg = colors.keyword, bold = true }) hi("SnacksDashboardKey", { fg = colors.keyword, bold = true }) hi("SnacksDashboardIcon", { fg = colors.func }) hi("SnacksDashboardDesc", { fg = colors.fg }) hi("SnacksDashboardFooter", { fg = colors.fg_dim }) -- Dashboard (legacy) hi("DashboardHeader", { fg = colors.keyword, bold = true }) hi("DashboardCenter", { fg = colors.fg }) hi("DashboardFooter", { fg = colors.fg_faint }) hi("DashboardShortCut", { fg = colors.keyword }) -- Lazy hi("LazyButton", { fg = colors.fg, bg = colors.bg_dim }) hi("LazyButtonActive", { fg = colors.fg, bg = colors.tag_sel, bold = true }) hi("LazyH1", { fg = colors.keyword, bold = true }) hi("LazySpecial", { fg = colors.func }) -- Mini statusline (Plan 9 accent colors for modes) hi("MiniStatuslineModeNormal", { fg = p9.white, bg = p9.bluegreen, bold = true }) hi("MiniStatuslineModeInsert", { fg = p9.white, bg = p9.darkgreen, bold = true }) hi("MiniStatuslineModeVisual", { fg = p9.white, bg = p9.purpleblue, bold = true }) hi("MiniStatuslineModeReplace", { fg = p9.white, bg = p9.b2_red, bold = true }) hi("MiniStatuslineModeCommand", { fg = colors.fg, bg = p9.darkyellow, bold = true }) -- Bufferline (tag bar style) hi("BufferLineFill", { bg = colors.tagbar }) hi("BufferLineBackground", { fg = colors.fg_dim, bg = colors.tagbar }) hi("BufferLineBuffer", { fg = colors.fg_dim, bg = colors.tagbar }) hi("BufferLineBufferSelected", { fg = colors.fg, bg = colors.bg, bold = true }) hi("BufferLineBufferVisible", { fg = colors.fg_dim, bg = colors.tagbar }) hi("BufferLineCloseButton", { fg = colors.fg_dim, bg = colors.tagbar }) hi("BufferLineCloseButtonSelected", { fg = colors.error, bg = colors.bg }) hi("BufferLineCloseButtonVisible", { fg = colors.fg_dim, bg = colors.tagbar }) hi("BufferLineIndicatorSelected", { fg = colors.tag_border, bg = colors.bg }) hi("BufferLineModified", { fg = colors.modified, bg = colors.tagbar }) hi("BufferLineModifiedSelected", { fg = colors.modified, bg = colors.bg }) hi("BufferLineSeparator", { fg = colors.tagbar, bg = colors.tagbar }) hi("BufferLineSeparatorSelected", { fg = colors.tagbar, bg = colors.bg }) -- Copilot hi("CopilotSuggestion", { fg = colors.fg_faint }) -- Lualine (if used instead of mini) hi("lualine_a_normal", { fg = p9.white, bg = p9.bluegreen, bold = true }) hi("lualine_a_insert", { fg = p9.white, bg = p9.darkgreen, bold = true }) hi("lualine_a_visual", { fg = p9.white, bg = p9.purpleblue, bold = true }) hi("lualine_a_replace", { fg = p9.white, bg = p9.b2_red, bold = true }) hi("lualine_a_command", { fg = colors.fg, bg = p9.darkyellow, bold = true }) hi("lualine_b_normal", { fg = colors.fg, bg = colors.tagbar }) hi("lualine_c_normal", { fg = colors.fg_dim, bg = colors.bg_dim }) end M.setup() return M