-- 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