mirror of
https://github.com/bgrolleman/dotfiles.git
synced 2026-06-26 07:20:43 +02:00
Cleanup nvim with Claude
This commit is contained in:
@@ -1,7 +1,21 @@
|
||||
-- Autocmds are automatically loaded on the VeryLazy event
|
||||
-- Default autocmds that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/autocmds.lua
|
||||
--
|
||||
-- Add any additional autocmds here
|
||||
-- with `vim.api.nvim_create_autocmd`
|
||||
--
|
||||
-- Or remove existing autocmds by their group name (which is prefixed with `lazyvim_` for the defaults)
|
||||
-- By this point noice.nvim has already replaced vim.notify
|
||||
|
||||
-- Log warnings and errors to file for debugging
|
||||
local log_path = vim.fn.stdpath("log") .. "/nvim_errors.log"
|
||||
local _notify = vim.notify
|
||||
vim.notify = function(msg, level, opts)
|
||||
if level and level >= vim.log.levels.WARN then
|
||||
local f = io.open(log_path, "a")
|
||||
if f then
|
||||
f:write(string.format(
|
||||
"[%s] %s: %s\n",
|
||||
os.date("%Y-%m-%d %H:%M:%S"),
|
||||
level == vim.log.levels.ERROR and "ERROR" or "WARN",
|
||||
tostring(msg)
|
||||
))
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
return _notify(msg, level, opts)
|
||||
end
|
||||
|
||||
@@ -1,12 +1,2 @@
|
||||
-- Keymaps are automatically loaded on the VeryLazy event
|
||||
-- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua
|
||||
-- Add any additional keymaps here
|
||||
--
|
||||
-- vim.api.nvim_set_keymap("i", "jj", "<Esc>", { noremap = false })
|
||||
|
||||
local wk = require("which-key")
|
||||
|
||||
wk.add({
|
||||
{ "<leader>N", group = "Notes" },
|
||||
{ "<leader>Nt", ":Journal<CR>", desc = "Today" },
|
||||
})
|
||||
-- Use legendary.nvim to add named commands to the command palette
|
||||
|
||||
@@ -18,8 +18,8 @@ vim.opt.rtp:prepend(lazypath)
|
||||
-- Make sure to setup `mapleader` and `maplocalleader` before
|
||||
-- loading lazy.nvim so that mappings are correct.
|
||||
-- This is also a good place to setup other settings (vim.opt)
|
||||
vim.g.mapleader = ","
|
||||
vim.g.maplocalleader = ","
|
||||
vim.g.mapleader = " "
|
||||
vim.g.maplocalleader = "\\"
|
||||
|
||||
-- Setup lazy.nvim
|
||||
require("lazy").setup({
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
|
||||
if not (vim.uv or vim.loop).fs_stat(lazypath) then
|
||||
local lazyrepo = "https://github.com/folke/lazy.nvim.git"
|
||||
local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
|
||||
if vim.v.shell_error ~= 0 then
|
||||
vim.api.nvim_echo({
|
||||
{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
|
||||
{ out, "WarningMsg" },
|
||||
{ "\nPress any key to exit..." },
|
||||
}, true, {})
|
||||
vim.fn.getchar()
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
vim.opt.rtp:prepend(lazypath)
|
||||
|
||||
require("lazy").setup({
|
||||
spec = {
|
||||
-- add LazyVim and import its plugins
|
||||
{ "LazyVim/LazyVim", import = "lazyvim.plugins" },
|
||||
-- import/override with your plugins
|
||||
{ import = "plugins" },
|
||||
},
|
||||
defaults = {
|
||||
-- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup.
|
||||
-- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default.
|
||||
lazy = false,
|
||||
-- It's recommended to leave version=false for now, since a lot the plugin that support versioning,
|
||||
-- have outdated releases, which may break your Neovim install.
|
||||
version = false, -- always use the latest git commit
|
||||
-- version = "*", -- try installing the latest stable version for plugins that support semver
|
||||
},
|
||||
install = { colorscheme = { "tokyonight", "habamax" } },
|
||||
checker = {
|
||||
enabled = true, -- check for plugin updates periodically
|
||||
notify = false, -- notify on update
|
||||
}, -- automatically check for plugin updates
|
||||
performance = {
|
||||
rtp = {
|
||||
-- disable some rtp plugins
|
||||
disabled_plugins = {
|
||||
"gzip",
|
||||
-- "matchit",
|
||||
-- "matchparen",
|
||||
-- "netrwPlugin",
|
||||
"tarPlugin",
|
||||
"tohtml",
|
||||
"tutor",
|
||||
"zipPlugin",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,3 +1,6 @@
|
||||
-- Options are automatically loaded before lazy.nvim startup
|
||||
-- Default options that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/options.lua
|
||||
-- Add any additional options here
|
||||
vim.opt.relativenumber = true
|
||||
vim.opt.scrolloff = 8
|
||||
vim.opt.wrap = false
|
||||
vim.opt.undofile = true
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
return {
|
||||
"jackMort/ChatGPT.nvim",
|
||||
event = "VeryLazy",
|
||||
config = function()
|
||||
require("chatgpt").setup({
|
||||
openai_params = {
|
||||
model = "gpt-4.1"
|
||||
}
|
||||
})
|
||||
end,
|
||||
dependencies = {
|
||||
"MunifTanjim/nui.nvim",
|
||||
"nvim-lua/plenary.nvim",
|
||||
"folke/trouble.nvim", -- optional
|
||||
"nvim-telescope/telescope.nvim"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
return {
|
||||
{ "zbirenbaum/copilot.lua", opts = { suggestion = { enabled = false } } },
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
-- since this is just an example spec, don't actually load anything here and return an empty spec
|
||||
-- stylua: ignore
|
||||
if true then return {} end
|
||||
|
||||
-- every spec file under the "plugins" directory will be loaded automatically by lazy.nvim
|
||||
--
|
||||
-- In your plugin files, you can:
|
||||
-- * add extra plugins
|
||||
-- * disable/enabled LazyVim plugins
|
||||
-- * override the configuration of LazyVim plugins
|
||||
return {
|
||||
-- add gruvbox
|
||||
{ "ellisonleao/gruvbox.nvim" },
|
||||
|
||||
-- Configure LazyVim to load gruvbox
|
||||
{
|
||||
"LazyVim/LazyVim",
|
||||
opts = {
|
||||
colorscheme = "gruvbox",
|
||||
},
|
||||
},
|
||||
|
||||
-- change trouble config
|
||||
{
|
||||
"folke/trouble.nvim",
|
||||
-- opts will be merged with the parent spec
|
||||
opts = { use_diagnostic_signs = true },
|
||||
},
|
||||
|
||||
-- disable trouble
|
||||
{ "folke/trouble.nvim", enabled = false },
|
||||
|
||||
-- override nvim-cmp and add cmp-emoji
|
||||
{
|
||||
"hrsh7th/nvim-cmp",
|
||||
dependencies = { "hrsh7th/cmp-emoji" },
|
||||
---@param opts cmp.ConfigSchema
|
||||
opts = function(_, opts)
|
||||
table.insert(opts.sources, { name = "emoji" })
|
||||
end,
|
||||
},
|
||||
|
||||
-- change some telescope options and a keymap to browse plugin files
|
||||
{
|
||||
"nvim-telescope/telescope.nvim",
|
||||
keys = {
|
||||
-- add a keymap to browse plugin files
|
||||
-- stylua: ignore
|
||||
{
|
||||
"<leader>fp",
|
||||
function() require("telescope.builtin").find_files({ cwd = require("lazy.core.config").options.root }) end,
|
||||
desc = "Find Plugin File",
|
||||
},
|
||||
},
|
||||
-- change some options
|
||||
opts = {
|
||||
defaults = {
|
||||
layout_strategy = "horizontal",
|
||||
layout_config = { prompt_position = "top" },
|
||||
sorting_strategy = "ascending",
|
||||
winblend = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- add pyright to lspconfig
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
---@class PluginLspOpts
|
||||
opts = {
|
||||
---@type lspconfig.options
|
||||
servers = {
|
||||
-- pyright will be automatically installed with mason and loaded with lspconfig
|
||||
pyright = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- add tsserver and setup with typescript.nvim instead of lspconfig
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
dependencies = {
|
||||
"jose-elias-alvarez/typescript.nvim",
|
||||
init = function()
|
||||
require("lazyvim.util").lsp.on_attach(function(_, buffer)
|
||||
-- stylua: ignore
|
||||
vim.keymap.set( "n", "<leader>co", "TypescriptOrganizeImports", { buffer = buffer, desc = "Organize Imports" })
|
||||
vim.keymap.set("n", "<leader>cR", "TypescriptRenameFile", { desc = "Rename File", buffer = buffer })
|
||||
end)
|
||||
end,
|
||||
},
|
||||
---@class PluginLspOpts
|
||||
opts = {
|
||||
---@type lspconfig.options
|
||||
servers = {
|
||||
-- tsserver will be automatically installed with mason and loaded with lspconfig
|
||||
tsserver = {},
|
||||
},
|
||||
-- you can do any additional lsp server setup here
|
||||
-- return true if you don't want this server to be setup with lspconfig
|
||||
---@type table<string, fun(server:string, opts:_.lspconfig.options):boolean?>
|
||||
setup = {
|
||||
-- example to setup with typescript.nvim
|
||||
tsserver = function(_, opts)
|
||||
require("typescript").setup({ server = opts })
|
||||
return true
|
||||
end,
|
||||
-- Specify * to use this function as a fallback for any server
|
||||
-- ["*"] = function(server, opts) end,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- for typescript, LazyVim also includes extra specs to properly setup lspconfig,
|
||||
-- treesitter, mason and typescript.nvim. So instead of the above, you can use:
|
||||
{ import = "lazyvim.plugins.extras.lang.typescript" },
|
||||
|
||||
-- add more treesitter parsers
|
||||
{
|
||||
"nvim-treesitter/nvim-treesitter",
|
||||
opts = {
|
||||
ensure_installed = {
|
||||
"bash",
|
||||
"html",
|
||||
"javascript",
|
||||
"json",
|
||||
"lua",
|
||||
"markdown",
|
||||
"markdown_inline",
|
||||
"python",
|
||||
"query",
|
||||
"regex",
|
||||
"tsx",
|
||||
"typescript",
|
||||
"vim",
|
||||
"yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- since `vim.tbl_deep_extend`, can only merge tables and not lists, the code above
|
||||
-- would overwrite `ensure_installed` with the new value.
|
||||
-- If you'd rather extend the default config, use the code below instead:
|
||||
{
|
||||
"nvim-treesitter/nvim-treesitter",
|
||||
opts = function(_, opts)
|
||||
-- add tsx and treesitter
|
||||
vim.list_extend(opts.ensure_installed, {
|
||||
"tsx",
|
||||
"typescript",
|
||||
})
|
||||
end,
|
||||
},
|
||||
|
||||
-- the opts function can also be used to change the default opts:
|
||||
{
|
||||
"nvim-lualine/lualine.nvim",
|
||||
event = "VeryLazy",
|
||||
opts = function(_, opts)
|
||||
table.insert(opts.sections.lualine_x, {
|
||||
function()
|
||||
return "😄"
|
||||
end,
|
||||
})
|
||||
end,
|
||||
},
|
||||
|
||||
-- or you can return new options to override all the defaults
|
||||
{
|
||||
"nvim-lualine/lualine.nvim",
|
||||
event = "VeryLazy",
|
||||
opts = function()
|
||||
return {
|
||||
--[[add your custom lualine config here]]
|
||||
}
|
||||
end,
|
||||
},
|
||||
|
||||
-- use mini.starter instead of alpha
|
||||
{ import = "lazyvim.plugins.extras.ui.mini-starter" },
|
||||
|
||||
-- add jsonls and schemastore packages, and setup treesitter for json, json5 and jsonc
|
||||
{ import = "lazyvim.plugins.extras.lang.json" },
|
||||
|
||||
-- add any tools you want to have installed below
|
||||
{
|
||||
"williamboman/mason.nvim",
|
||||
opts = {
|
||||
ensure_installed = {
|
||||
"stylua",
|
||||
"shellcheck",
|
||||
"shfmt",
|
||||
"flake8",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
return {
|
||||
"jghauser/follow-md-links.nvim",
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
return {
|
||||
'nvim-lualine/lualine.nvim',
|
||||
dependencies = { 'nvim-tree/nvim-web-devicons' }
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
return {
|
||||
"nvim-neo-tree/neo-tree.nvim",
|
||||
branch = "v3.x",
|
||||
dependencies = {
|
||||
"nvim-lua/plenary.nvim",
|
||||
"nvim-tree/nvim-web-devicons", -- not strictly required, but recommended
|
||||
"MunifTanjim/nui.nvim",
|
||||
-- {"3rd/image.nvim", opts = {}}, -- Optional image support in preview window: See `# Preview Mode` for more information
|
||||
},
|
||||
lazy = false, -- neo-tree will lazily load itself
|
||||
---@module "neo-tree"
|
||||
---@type neotree.Config?
|
||||
opts = {
|
||||
-- fill any relevant options here
|
||||
},
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
return {
|
||||
"nvim-neorg/neorg",
|
||||
lazy = false, -- Disable lazy loading as some `lazy.nvim` distributions set `lazy = true` by default
|
||||
version = "*", -- Pin Neorg to the latest stable release
|
||||
config = function()
|
||||
require("neorg").setup({
|
||||
load = {
|
||||
["core.defaults"] = {}, -- Loads default behaviour
|
||||
["core.concealer"] = {}, -- Adds pretty icons to your documents
|
||||
["core.ui.calendar"] = {},
|
||||
["core.completion"] = { config = { engine = { module_name = "external.lsp-completion" }, name = "[Norg]" } },
|
||||
["core.esupports.metagen"] = { config = { type = "auto", update_date = true } },
|
||||
["core.qol.toc"] = {},
|
||||
["core.qol.todo_items"] = {},
|
||||
["core.looking-glass"] = {},
|
||||
["core.presenter"] = { config = { zen_mode = "zen-mode" } },
|
||||
["core.export"] = {},
|
||||
["core.export.markdown"] = { config = { extensions = "all" } },
|
||||
["core.summary"] = {},
|
||||
["core.tangle"] = { config = { report_on_empty = false } },
|
||||
["core.dirman"] = { -- Manages Neorg workspaces
|
||||
config = {
|
||||
workspaces = {
|
||||
notes = "~/Notes.neorg",
|
||||
},
|
||||
default_workspace = "notes",
|
||||
},
|
||||
},
|
||||
["external.interim-ls"] = {
|
||||
config = {
|
||||
-- default config shown
|
||||
completion_provider = {
|
||||
-- Enable or disable the completion provider
|
||||
enable = true,
|
||||
|
||||
-- Show file contents as documentation when you complete a file name
|
||||
documentation = true,
|
||||
|
||||
-- Try to complete categories provided by Neorg Query. Requires `benlubas/neorg-query`
|
||||
categories = false,
|
||||
|
||||
-- suggest heading completions from the given file for `{@x|}` where `|` is your cursor
|
||||
-- and `x` is an alphanumeric character. `{@name}` expands to `[name]{:$/people:# name}`
|
||||
people = {
|
||||
enable = false,
|
||||
|
||||
-- path to the file you're like to use with the `{@x` syntax, relative to the
|
||||
-- workspace root, without the `.norg` at the end.
|
||||
-- ie. `folder/people` results in searching `$/folder/people.norg` for headings.
|
||||
-- Note that this will change with your workspace, so it fails silently if the file
|
||||
-- doesn't exist
|
||||
path = "people",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
["core.keybinds"] = {
|
||||
config = {
|
||||
default_keybinds = true,
|
||||
neorg_leader = "<Leader>n", -- Change this to whatever you want
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
end,
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
return {
|
||||
"akinsho/toggleterm.nvim",
|
||||
tag = "*",
|
||||
keys = {
|
||||
{ "<leader>td", "<cmd>ToggleTerm size=40 dir=~ direction=horizontal<cr>", "Open Horizontal terminal in home directory"}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
return {
|
||||
"nvim-treesitter/nvim-treesitter"
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
return {
|
||||
"folke/twilight.nvim",
|
||||
opts = {
|
||||
-- your configuration comes here
|
||||
-- or leave it empty to use the default settings
|
||||
-- refer to the configuration section below
|
||||
},
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
return {
|
||||
"folke/which-key.nvim",
|
||||
event = "VeryLazy",
|
||||
opts = {
|
||||
-- your configuration comes here
|
||||
-- or leave it empty to use the default settings
|
||||
-- refer to the configuration section below
|
||||
},
|
||||
keys = {
|
||||
{
|
||||
{ "<leader>N", group = "Neorg" },
|
||||
{ "<leader>Nt", ":Neorg journal today<CR>", desc = "Today" },
|
||||
},
|
||||
},
|
||||
}
|
||||
--{ "<leader>c", group = "ChatGPT" },
|
||||
--{ "<leader>cc", ":ChatGPT<CR>", desc = "ChatGPT" },
|
||||
--{ "<leader>ce", ":ChatGPTEditWithInstructions<CR>", desc = "ChatGPT Edit Selection with Instructions" },
|
||||
@@ -1,7 +0,0 @@
|
||||
return {
|
||||
"rmagatti/auto-session",
|
||||
lazy = false,
|
||||
opts = {
|
||||
suppressed_dirs = { "~/", "~/Projects", "~/Downloads", "/" },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
return {
|
||||
"greggh/claude-code.nvim",
|
||||
dependencies = { "nvim-lua/plenary.nvim" },
|
||||
config = function()
|
||||
require("claude-code").setup({
|
||||
window = {
|
||||
position = "vertical",
|
||||
split_ratio = 0.4,
|
||||
},
|
||||
})
|
||||
end,
|
||||
keys = {
|
||||
{ "<leader>cc", "<cmd>ClaudeCode<CR>", desc = "Claude Code: Toggle" },
|
||||
{ "<leader>cf", "<cmd>ClaudeCodeFocus<CR>", desc = "Claude Code: Focus" },
|
||||
},
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
return {
|
||||
"benlubas/neorg-interim-ls",
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
return {
|
||||
"jakobkhansen/journal.nvim",
|
||||
config = function()
|
||||
require("journal").setup({
|
||||
filetype = "md", -- Filetype to use for new journal entries
|
||||
root = "~/Notes/Personal/journals", -- Root directory for journal entries
|
||||
date_format = "%Y-%m-%d", -- Date format for `:Journal <date-modifier>`
|
||||
autocomplete_date_modifier = "end", -- "always"|"never"|"end". Enable date modifier autocompletion
|
||||
|
||||
-- Configuration for journal entries
|
||||
journal = {
|
||||
-- Default configuration for `:Journal <date-modifier>`
|
||||
format = "%Y_%m_%d",
|
||||
template = "# %A %B %d %Y\n",
|
||||
frequency = { day = 1 },
|
||||
|
||||
-- Nested configurations for `:Journal <type> <type> ... <date-modifier>`
|
||||
entries = {
|
||||
day = {
|
||||
format = "%Y_%m_%d", -- Format of the journal entry in the filesystem.
|
||||
template = "# %A %B %d %Y\n", -- Optional. Template used when creating a new journal entry
|
||||
frequency = { day = 1 }, -- Optional. The frequency of the journal entry. Used for `:Journal next`, `:Journal -2` etc
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
end,
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
return {
|
||||
"mrjones2014/legendary.nvim",
|
||||
priority = 10000,
|
||||
lazy = false,
|
||||
dependencies = { "nvim-telescope/telescope.nvim" },
|
||||
opts = {
|
||||
telescope = { auto_register_which_key = false },
|
||||
keymaps = {
|
||||
{ "<leader>cc", description = "Claude Code: Toggle terminal" },
|
||||
{ "<leader>cf", description = "Claude Code: Focus terminal" },
|
||||
},
|
||||
},
|
||||
keys = {
|
||||
{ "<leader><leader>", "<cmd>Legendary<CR>", desc = "Command Palette" },
|
||||
{ "<C-p>", "<cmd>Legendary<CR>", desc = "Command Palette", mode = { "n", "i" } },
|
||||
},
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
-- Configuration Documentation https://github.com/jakewvincent/mkdnflow.nvim?tab=readme-ov-file#%EF%B8%8F-configuration
|
||||
return {
|
||||
"jakewvincent/mkdnflow.nvim",
|
||||
config = function()
|
||||
require("mkdnflow").setup({
|
||||
-- Config goes here; leave blank for defaults
|
||||
perspective = {
|
||||
priority = "first",
|
||||
root_tell = false,
|
||||
},
|
||||
new_file_template = {
|
||||
use_template = true,
|
||||
placeholders = {
|
||||
before = {
|
||||
title = "link_title",
|
||||
date = "os_date",
|
||||
},
|
||||
after = {},
|
||||
},
|
||||
template = "# {{ title }}",
|
||||
},
|
||||
links = {
|
||||
style = "markdown",
|
||||
name_is_source = false,
|
||||
conceal = false,
|
||||
context = 0,
|
||||
implicit_extension = nil,
|
||||
transform_implicit = false,
|
||||
transform_explicit = function(text)
|
||||
text = text:gsub(" ", "-")
|
||||
text = text:lower()
|
||||
return text
|
||||
end,
|
||||
create_on_follow_failure = true,
|
||||
},
|
||||
})
|
||||
end,
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
return {
|
||||
"stevearc/oil.nvim",
|
||||
dependencies = { "nvim-tree/nvim-web-devicons" },
|
||||
lazy = false,
|
||||
opts = {
|
||||
default_file_explorer = true,
|
||||
columns = { "icon" },
|
||||
view_options = {
|
||||
show_hidden = true,
|
||||
},
|
||||
},
|
||||
keys = {
|
||||
{ "-", "<cmd>Oil<CR>", desc = "Open parent directory" },
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user