refactor(nvim): streamline Neovim configuration and plugin management

This commit is contained in:
Prad Nukala committed 2025-10-22 10:59:55 -04:00
1 parent 06e0bab7dd
commit bdf8ad1bb0
27 files changed
+1797 -476

No files matched your search

+182
View File
@@ -0,0 +1,182 @@
# Code Templates
Essential templates for modern development with Cosmos SDK, Protobuf, and Vite+Cloudflare.
## 🚀 Usage
### Quick Access
- Press `<C-a><C-t>` to open the template picker
- Or use `:TemplateSnacks` command
### Template Variables
Templates support the following placeholders:
- `{{_date_}}` - Current date and time
- `{{_cursor_}}` - Cursor position after insertion
- `{{_file_name_}}` - Current file name (without extension)
- `{{_camel_case_file_}}` - File name converted to CamelCase
- `{{_upper_file_}}` - File name in UPPERCASE
- `{{_author_}}` - Author name (configured in plugin)
- `{{_email_}}` - Email address (configured in plugin)
- `{{_variable_}}` - Prompts for custom variable name
- `{{_lua:<expr>_}}` - Execute Lua expression
## 📁 Available Templates
### Cosmos SDK (Go) - `/cosmos`
#### `keeper.go.tpl`
Creates a Cosmos SDK keeper with store management and parameter store.
**Use for:** Module keeper implementation
**Variables:** Uses `{{_file_name_}}` for module name
#### `msg_server.go.tpl`
Creates a message server implementation for handling transactions.
**Use for:** Transaction message handlers
**Variables:** `{{_variable_}}` for the message type name
#### `query_server.go.tpl`
Creates a query server implementation for handling read queries.
**Use for:** Query handlers for module state
**Variables:** `{{_variable_}}` for the query method name
#### `handler.go.tpl`
Creates a message handler router for the module.
**Use for:** Main message routing logic
### Protobuf - `/proto`
#### `message.proto.tpl`
Creates a basic protobuf message definition.
**Use for:** Data structures and types
**Variables:** `{{_variable_}}` for the message name
#### `tx.proto.tpl`
Creates a transaction message service with RPC definitions.
**Use for:** Transaction (Msg) service definitions
**Variables:** `{{_variable_}}` for the transaction method name
#### `query.proto.tpl`
Creates a query service with gRPC and HTTP annotations.
**Use for:** Query service definitions with REST endpoints
**Variables:** `{{_variable_}}` for the query method name
### Vite + Cloudflare + TanStack - `/vite`
#### `worker.ts.tpl`
Creates a Cloudflare Worker with proper TypeScript types.
**Use for:** Cloudflare Worker scripts
**File type:** TypeScript
#### `pages-function.ts.tpl`
Creates a Cloudflare Pages Function.
**Use for:** Cloudflare Pages API routes
**File type:** TypeScript
#### `page.tsx.tpl`
Creates a TanStack Router page component.
**Use for:** Full page routes with TanStack Router
**File type:** TypeScript React
#### `component.tsx.tpl`
Creates a memoized React component with TypeScript.
**Use for:** Reusable React components
**File type:** TypeScript React
#### `hook.ts.tpl`
Creates a custom React hook with TypeScript.
**Use for:** Reusable React hooks
**File type:** TypeScript
#### `api.ts.tpl`
Creates a TanStack Query API client with CRUD operations.
**Use for:** API integration with TanStack Query
**File type:** TypeScript
**Includes:** Query keys, fetch functions, and hooks
## 💡 Examples
### Creating a Cosmos SDK Message Server
1. Create/open a file: `msg_server_create_post.go`
2. Press `<C-a><C-t>`
3. Select `msg_server.go.tpl`
4. Enter variable name when prompted: `CreatePost`
5. Template is inserted with all placeholders filled
### Creating a TanStack Query API
1. Create/open a file: `posts.ts`
2. Press `<C-a><C-t>`
3. Select `api.ts.tpl`
4. Template creates full API client with:
- Query keys
- Fetch functions
- React hooks for queries and mutations
### Creating a React Component
1. Create/open a file: `user_card.tsx`
2. Press `<C-a><C-t>`
3. Select `component.tsx.tpl`
4. Component created with name `UserCard` (auto-converted to CamelCase)
## 🎨 Customization
### Adding Your Own Templates
1. Create a new `.tpl` file in the templates directory
2. Add filetype marker as first line: `;; <filetype>`
3. Use template variables as needed
4. Save and use with `<C-a><C-t>`
Example:
```typescript
;; typescript
/**
* {{_file_name_}}
* @author {{_author_}}
*/
export const {{_camel_case_file_}} = {{_cursor_}}
```
### Template Organization
- Use subdirectories to organize templates by category
- Template picker shows category in selection: `[category] filename`
- Templates are filtered by current file type automatically
## 🔧 Configuration
Edit template configuration in `lua/plugins/template.lua`:
```lua
template.setup {
temp_dir = vim.fn.stdpath "config" .. "/templates",
author = "Your Name",
email = "your.email@example.com",
}
```
## 📚 Resources
- [template.nvim GitHub](https://github.com/glepnir/template.nvim)
- [Cosmos SDK Docs](https://docs.cosmos.network/)
- [Cloudflare Workers Docs](https://developers.cloudflare.com/workers/)
- [TanStack Router](https://tanstack.com/router)
- [TanStack Query](https://tanstack.com/query)
+27
View File
@@ -0,0 +1,27 @@
;; go
package {{_file_name_}}
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/sonr-io/sonr/x/{{_file_name_}}/keeper"
"github.com/sonr-io/sonr/x/{{_file_name_}}/types"
)
// NewHandler returns a handler for {{_file_name_}} module messages
func NewHandler(k keeper.Keeper) sdk.Handler {
msgServer := keeper.NewMsgServerImpl(k)
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
{{_cursor_}}
default:
errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg)
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
}
}
}
+39
View File
@@ -0,0 +1,39 @@
;; go
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sonr-io/sonr/x/{{_file_name_}}/types"
)
type Keeper struct {
storeKey sdk.StoreKey
cdc codec.BinaryCodec
paramstore paramtypes.Subspace
}
func NewKeeper(
cdc codec.BinaryCodec,
storeKey sdk.StoreKey,
ps paramtypes.Subspace,
) *Keeper {
// set KeyTable if it has not already been set
if !ps.HasKeyTable() {
ps = ps.WithKeyTable(types.ParamKeyTable())
}
return &Keeper{
cdc: cdc,
storeKey: storeKey,
paramstore: ps,
}
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/{{_file_name_}}")
}
{{_cursor_}}
+43
View File
@@ -0,0 +1,43 @@
;; go
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sonr-io/sonr/x/{{_file_name_}}/types"
)
type msgServer struct {
Keeper
}
// NewMsgServerImpl returns an implementation of the {{_camel_case_file_}} MsgServer interface
// for the provided Keeper.
func NewMsgServerImpl(keeper Keeper) types.MsgServer {
return &msgServer{Keeper: keeper}
}
var _ types.MsgServer = msgServer{}
// {{_variable_}} implements types.MsgServer
func (k msgServer) {{_variable_}}(goCtx context.Context, msg *types.Msg{{_variable_}}) (*types.Msg{{_variable_}}Response, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// Validate message
if err := msg.ValidateBasic(); err != nil {
return nil, err
}
{{_cursor_}}
// Emit event
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventType{{_variable_}},
sdk.NewAttribute(types.AttributeKeyCreator, msg.Creator),
),
)
return &types.Msg{{_variable_}}Response{}, nil
}
+36
View File
@@ -0,0 +1,36 @@
;; go
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sonr-io/sonr/x/{{_file_name_}}/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type queryServer struct {
Keeper
}
// NewQueryServerImpl returns an implementation of the {{_camel_case_file_}} QueryServer interface
// for the provided Keeper.
func NewQueryServerImpl(keeper Keeper) types.QueryServer {
return &queryServer{Keeper: keeper}
}
var _ types.QueryServer = queryServer{}
// {{_variable_}} implements types.QueryServer
func (k queryServer) {{_variable_}}(goCtx context.Context, req *types.Query{{_variable_}}Request) (*types.Query{{_variable_}}Response, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
ctx := sdk.UnwrapSDKContext(goCtx)
{{_cursor_}}
return &types.Query{{_variable_}}Response{}, nil
}
+17
View File
@@ -0,0 +1,17 @@
;; proto
syntax = "proto3";
package sonr.{{_file_name_}}.v1;
option go_package = "github.com/sonr-io/sonr/x/{{_file_name_}}/types";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "amino/amino.proto";
// {{_variable_}} defines the {{_variable_}} message
message {{_variable_}} {
option (gogoproto.equal) = true;
option (amino.name) = "sonr/{{_file_name_}}/{{_variable_}}";
{{_cursor_}}
}
+29
View File
@@ -0,0 +1,29 @@
;; proto
syntax = "proto3";
package sonr.{{_file_name_}}.v1;
option go_package = "github.com/sonr-io/sonr/x/{{_file_name_}}/types";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/query/v1/query.proto";
// Query defines the gRPC querier service
service Query {
// {{_variable_}} queries the {{_variable_}}
rpc {{_variable_}}(Query{{_variable_}}Request) returns (Query{{_variable_}}Response) {
option (cosmos.query.v1.module_query_safe) = true;
option (google.api.http).get = "/sonr/{{_file_name_}}/v1/{{_variable_}}";
}
}
// Query{{_variable_}}Request is the request type for the Query/{{_variable_}} RPC method
message Query{{_variable_}}Request {
{{_cursor_}}
}
// Query{{_variable_}}Response is the response type for the Query/{{_variable_}} RPC method
message Query{{_variable_}}Response {
}
+30
View File
@@ -0,0 +1,30 @@
;; proto
syntax = "proto3";
package sonr.{{_file_name_}}.v1;
option go_package = "github.com/sonr-io/sonr/x/{{_file_name_}}/types";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/msg/v1/msg.proto";
import "amino/amino.proto";
// Msg defines the {{_file_name_}} Msg service
service Msg {
option (cosmos.msg.v1.service) = true;
// {{_variable_}} defines the {{_variable_}} RPC method
rpc {{_variable_}}(Msg{{_variable_}}) returns (Msg{{_variable_}}Response);
}
// Msg{{_variable_}} defines the {{_variable_}} message
message Msg{{_variable_}} {
option (cosmos.msg.v1.signer) = "creator";
option (amino.name) = "sonr/{{_file_name_}}/{{_variable_}}";
string creator = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
{{_cursor_}}
}
// Msg{{_variable_}}Response defines the {{_variable_}} response
message Msg{{_variable_}}Response {}
+58
View File
@@ -0,0 +1,58 @@
;; typescript
/**
* {{_camel_case_file_}} API Client
* @author {{_author_}}
* @created {{_date_}}
*/
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
// API Types
interface {{_camel_case_file_}}Data {
{{_cursor_}}
}
// Query Keys
export const {{_file_name_}}Keys = {
all: ['{{_file_name_}}'] as const,
lists: () => [...{{_file_name_}}Keys.all, 'list'] as const,
list: (filters: string) => [...{{_file_name_}}Keys.lists(), { filters }] as const,
details: () => [...{{_file_name_}}Keys.all, 'detail'] as const,
detail: (id: string) => [...{{_file_name_}}Keys.details(), id] as const,
}
// API Functions
async function fetch{{_camel_case_file_}}(id: string): Promise<{{_camel_case_file_}}Data> {
const response = await fetch(`/api/{{_file_name_}}/${id}`)
if (!response.ok) throw new Error('Failed to fetch {{_file_name_}}')
return response.json()
}
async function create{{_camel_case_file_}}(data: Partial<{{_camel_case_file_}}Data>): Promise<{{_camel_case_file_}}Data> {
const response = await fetch('/api/{{_file_name_}}', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) throw new Error('Failed to create {{_file_name_}}')
return response.json()
}
// Hooks
export function use{{_camel_case_file_}}(id: string) {
return useQuery({
queryKey: {{_file_name_}}Keys.detail(id),
queryFn: () => fetch{{_camel_case_file_}}(id),
})
}
export function useCreate{{_camel_case_file_}}() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: create{{_camel_case_file_}},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: {{_file_name_}}Keys.lists() })
},
})
}
+22
View File
@@ -0,0 +1,22 @@
;; typescriptreact
/**
* {{_camel_case_file_}} Component
* @author {{_author_}}
* @created {{_date_}}
*/
import { memo } from 'react'
interface {{_camel_case_file_}}Props {
{{_cursor_}}
}
export const {{_camel_case_file_}} = memo<{{_camel_case_file_}}Props>(({ }) => {
return (
<div>
</div>
)
})
{{_camel_case_file_}}.displayName = '{{_camel_case_file_}}'
+24
View File
@@ -0,0 +1,24 @@
;; typescript
/**
* {{_camel_case_file_}} Hook
* @author {{_author_}}
* @created {{_date_}}
*/
import { useState, useEffect } from 'react'
interface Use{{_camel_case_file_}}Options {
{{_cursor_}}
}
export function use{{_camel_case_file_}}(options?: Use{{_camel_case_file_}}Options) {
const [data, setData] = useState()
useEffect(() => {
// Hook logic here
}, [])
return {
data,
}
}
+23
View File
@@ -0,0 +1,23 @@
;; typescriptreact
/**
* {{_camel_case_file_}} Page Component
* @author {{_author_}}
* @created {{_date_}}
*/
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/{{_file_name_}}')({
component: {{_camel_case_file_}}Page,
})
function {{_camel_case_file_}}Page() {
{{_cursor_}}
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-6">{{_camel_case_file_}}</h1>
</div>
)
}
+20
View File
@@ -0,0 +1,20 @@
;; typescript
/**
* Cloudflare Pages Function - {{_file_name_}}
* @author {{_author_}}
* @created {{_date_}}
*/
interface Env {
// Add your environment bindings here
}
export const onRequest: PagesFunction<Env> = async (context) => {
const { request, env, params } = context
{{_cursor_}}
return new Response(JSON.stringify({ success: true }), {
headers: { 'Content-Type': 'application/json' },
})
}
+23
View File
@@ -0,0 +1,23 @@
;; typescript
/**
* Cloudflare Worker - {{_file_name_}}
* @author {{_author_}}
* @created {{_date_}}
*/
export interface Env {
// Add your environment bindings here
// Example: DB: D1Database
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
{{_cursor_}}
return new Response('Hello World!', {
headers: { 'Content-Type': 'text/plain' },
});
},
} satisfies ExportedHandler<Env>;