local ls = require 'luasnip' local s = ls.snippet local sn = ls.snippet_node local fn = ls.function_node local t = ls.text_node local c = ls.choice_node local i = ls.insert_node local f = ls.function_node local d = ls.dynamic_node local fmt = require('luasnip.extras.fmt').fmt local rep = require('luasnip.extras').rep local extend_decorator = require 'luasnip.util.extend_decorator' local fmta = extend_decorator.apply(fmt, { delimiters = '#~' }) local utils = require 'snippets.snip_utils' local tr = utils.tr local etr = utils.etr local atr = utils.atr local ctr = utils.ctr local bs = utils.bs local function psr_namespace(_, snip) local path = vim.fn.expand '%' -- Get the directory of the path local dir = vim.fs.dirname(path) -- Loop through parent directories to find composer.json while dir ~= '/' and dir ~= nil do local composer_json_path = dir .. '/composer.json' if vim.fn.filereadable(composer_json_path) == 1 then break end dir = vim.fs.dirname(dir) end -- If no composer.json found, return empty string if dir == '/' or dir == nil then return '' end -- Decode composer.json and get PSR-4 autoload mappings local composer = vim.json.decode(vim.iter(vim.fn.readfile(dir .. '/composer.json')):join '') local psr4 = composer['autoload'] and composer['autoload']['psr-4'] -- If no PSR-4 mappings, return empty string if not psr4 then return '' end -- Get the relative path from the composer.json directory local relative_path = path:sub(#dir + 2) -- Loop through PSR-4 mappings for namespace, map in pairs(psr4) do -- Check if the relative path matches the mapping if relative_path:match('^' .. map:gsub('/', '%%/')) then -- Extract the suffix of the path after the mapping, removing the filename local suffix = relative_path:sub(#map + 1):match '^(.*)/[^/]+%.php$' or '' local trimmed = namespace:gsub('\\$', '') return trimmed .. (suffix ~= '' and ('\\' .. suffix:gsub('/', '\\')) or '') end end end local function class_name(args, snip) local filename = snip.env.TM_FILENAME or '' return filename:match '([^%.]+)' or 'ClassName' end return { --------------- -- DEBUGGING -- --------------- s(etr('du ', 'Dump a variable to the dump server'), fmta('dump(#~);', { i(0) })), bs(atr('du ', 'Dump a variable to the dump server'), fmta('dump(#~)', { i(0) })), s(etr('r ', 'ray'), fmta('ray(#~);', { i(0) })), bs(atr('r ', 'ray'), fmta('ray(#~)', { i(0) })), s(etr('dt ', 'Dump PHPStan type definition'), fmta('\\PhpStan\\dumpType(#~);', { i(0) })), s( etr('ql ', 'Log all queries'), fmta( [[ \Illuminate\Support\Facades\DB::listen(function (\Illuminate\Database\Events\QueryExecuted $e) { dump($e->sql, $e->bindings); }); #~ ]], { i(0) } ) ), -------------- -- COMMENTS -- -------------- s(etr('/**', 'Docblock comment'), { c(1, { sn( nil, fmta( [[ /** * #~ */ ]], { i(1) } ) ), sn(nil, fmta('/** #~ */', { i(1) })), }), }), s(etr('@v', '@var docblock'), fmta('/** @var #~ $#~ */', { i(1), i(0) })), s(ctr('@v', '@var docblock'), fmta('@var #~ $#~', { i(1), i(0) })), s(ctr('* @pr', 'Class property docblock'), fmta('* @property #~ $#~', { i(1), i(0) })), s(ctr('* @pb', 'Class boolean property docblock'), fmta('* @property bool $#~', { i(0) })), s(ctr('* @pi', 'Class int property docblock'), fmta('* @property int $#~', { i(0) })), s(ctr('* @ps', 'Class string property docblock'), fmta('* @property string $#~', { i(0) })), s(ctr('* @pc', 'Class collection property docblock'), fmta('* @property \\Illuminate\\Database\\Eloquent\\Collection<#~> $#~', { i(1), i(0) })), s(ctr('* @pd', 'Class date property docblock'), fmta('* @property \\Illuminate\\Support\\Carbon $#~', { i(0) })), s( etr('@pm', 'Model magic properties docblock'), fmta( [[ /** * @property int $id * #~ * @property \Illuminate\Support\Carbon $created_at * @property \Illuminate\Support\Carbon $updated_at * * Relationships * #~ */ ]], { i(1), i(0) } ) ), ------------ -- SYNTAX -- ------------ s( etr('if ', 'if block'), fmta( [[ if (#~) { #~ } ]], { i(1), i(0) } ) ), s( etr('fe ', 'foreach block'), fmta( [[ foreach (#~ as #~) { #~ } ]], { i(1), i(2), i(0) } ) ), s(etr('foreach', 'foreach block'), fmta('fe', {})), s( etr('for ', 'for block'), fmta( [[ for (#~; #~; #~) { #~ } ]], { i(1, '$i'), i(2), i(3, '$i++'), i(0) } ) ), s(etr('return ', 'Add semicolon after return'), fmta('return #~;', { i(0) })), s(atr(' use ', 'Add use to function'), fmta(' use (#~)', { i(0) })), s(etr('rt ', 'return alias'), fmta('return #~;', { i(0) })), bs( atr('fn ', 'Shorthand function block'), c(0, { sn(nil, fmta('fn (#~) => #~', { i(1), i(2) })), sn( nil, fmta( [[ function (#~) { #~ } ]], { i(1), i(2) } ) ), }) ), bs( atr('fun ', 'Shorthand function block'), c(0, { sn( nil, fmta( [[ function (#~) { #~ } ]], { i(1), i(2) } ) ), sn( nil, fmta( [[ function (#~) use (#~) { #~ } ]], { i(1), i(2), i(3) } ) ), }) ), s( etr('con', 'Constructor function block'), c(0, { sn( nil, fmta( [[ public function __construct(#~) { #~ } ]], { i(1), i(2) } ) ), sn( nil, fmta( [[ public function __construct( #~ ) { #~ } ]], { i(1), i(2) } ) ), }) ), bs(atr('function', 'Shorthand function block'), fmta('fun', {})), bs(atr('s%$', 'string type parameter'), fmta('string $#~', { i(0, 'var') })), bs(atr('i%$', 'int type parameter'), fmta('int $#~', { i(0, 'var') })), bs(atr('b%$', 'bool type parameter'), fmta('bool $#~', { i(0, 'var') })), bs(atr('a%$', 'array type parameter'), fmta('array $#~', { i(0, 'var') })), s(atr('$ ', 'Expand $this->'), fmta('$this->#~', { i(0) })), bs( atr('am ', 'array_map function'), c(0, { sn(nil, fmta('array_map(fn (#~) => #~, #~)', { i(2), i(3), i(1) })), sn( nil, fmta( [[ array_map(function (#~) { #~ }, #~) ]], { i(2), i(0), i(1) } ) ), }) ), bs(atr('array_map', 'array_map function'), fmta('am', {})), bs( atr('af ', 'array_filter function'), c(0, { sn(nil, fmta('array_filter(#~, fn (#~) => #~)', { i(1), i(2), i(3) })), sn( nil, fmta( [[ array_filter(#~, function (#~) { #~ }) ]], { i(1), i(2), i(0) } ) ), }) ), bs(atr('([^%w])array_filter', 'array_filter function'), fmta('af', {})), s( etr('php', 'php class'), fmta( [[ */ public function #~(): BelongsTo { return $this->belongsTo(#~::class); } ]], { rep(1), i(0), i(1) } ) ), s( etr('hm', 'hasMany Laravel relationship method'), fmta( [[ /** * @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\#~, $this> */ public function #~(): HasMany { return $this->hasOne(#~::class); } ]], { rep(1), i(0), i(1) } ) ), s( etr('ho', 'hasOne Laravel relationship method'), fmta( [[ /** * @return \Illuminate\Database\Eloquent\Relations\HasOne<\App\Models\#~, $this> */ public function #~(): HasOne { return $this->hasOne(#~::class); } ]], { rep(1), i(0), i(1) } ) ), s( etr('bm', 'belongsToMany Laravel relationship method'), fmta( [[ /** * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<\App\Models\#~, $this> */ public function #~(): BelongsToMany { return $this->belongsToMany(#~::class, #~); } ]], { rep(1), i(2), i(1), i(0) } ) ), s( atr('->wr', 'Eloquent where method'), c(0, { sn(nil, fmta("->where('#~', #~)", { i(1), i(0) })), sn(nil, fmta('->where(fn ($query) => #~)', { i(0) })), sn( nil, fmta( [[ ->where(function ($query) { #~ }) ]], { i(0) } ) ), sn( nil, fmta( [[ ->where(function ($query) use (#~) { #~ }) ]], { i(1), i(0) } ) ), }) ), s(atr('->wi', 'Eloquent where in method'), fmta("->whereIn('#~', #~)", { i(1), i(0) })), s(atr('->wn', 'Eloquent where not in method'), fmta("->whereNotIn('#~', #~)", { i(1), i(0) })), s( atr('->wh', 'Eloquent where has method'), c(0, { sn(nil, fmta("->whereHas('#~')", { i(1) })), sn(nil, fmta("->whereHas('#~', fn ($query) => #~)", { i(1), i(0) })), sn( nil, fmta( [[ ->whereHas('#~', function ($query) { #~ }) ]], { i(1), i(0) } ) ), sn( nil, fmta( [[ ->whereHas('#~', function ($query) use (#~) { #~ }) ]], { i(1), i(2), i(0) } ) ), }) ), s( atr('->we', 'Eloquent where exists method'), c(0, { sn(nil, fmta('->whereExists(fn ($query) => #~)', { i(0) })), sn( nil, fmta( [[ ->whereExists(function ($query) { #~ }) ]], { i(0) } ) ), sn( nil, fmta( [[ ->whereExists(function ($query) use (#~) { #~ }) ]], { i(1), i(0) } ) ), }) ), }