Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fa5938a18
|
||
|
|
dc73051719
|
||
|
|
f54d3880ff
|
||
|
|
a200688ec2 | ||
|
|
9ec0470c9c |
No files matched your search
@@ -0,0 +1,44 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# All files
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Rust files
|
||||
[*.rs]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# YAML files
|
||||
[*.{yml,yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Markdown files
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# TOML files
|
||||
[*.toml]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Shell scripts
|
||||
[*.{sh,bash,zsh,fish}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Makefile
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [yourusername]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective name
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2', 'link3', 'link4']
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve kfmtbox
|
||||
title: '[BUG] '
|
||||
labels: ['bug', 'needs-triage']
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## 🐛 Bug Description
|
||||
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
## 🔄 Steps to Reproduce
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Run command: `...`
|
||||
2. With input: `...`
|
||||
3. See error: `...`
|
||||
|
||||
## 🎯 Expected Behavior
|
||||
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
## 📸 Actual Behavior
|
||||
|
||||
A clear and concise description of what actually happened.
|
||||
|
||||
## 💻 Environment
|
||||
|
||||
**OS:** [e.g. macOS 13.0, Ubuntu 22.04, Windows 11]
|
||||
**Rust version:** [e.g. 1.70.0]
|
||||
**kfmtbox version:** [e.g. 0.1.0]
|
||||
**Terminal:** [e.g. iTerm2, Windows Terminal, GNOME Terminal]
|
||||
|
||||
## 📝 Sample Input
|
||||
|
||||
If applicable, provide the exact input that triggers the bug:
|
||||
|
||||
```bash
|
||||
echo "your input here" | kfmtbox --filetype rs
|
||||
```
|
||||
|
||||
## 📋 Additional Context
|
||||
|
||||
Add any other context about the problem here.
|
||||
|
||||
## 🔍 Possible Solution
|
||||
|
||||
If you have ideas on how to fix this bug, please describe them here.
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
- [ ] I have searched existing issues to ensure this is not a duplicate
|
||||
- [ ] I have provided all the information requested above
|
||||
- [ ] I have tested this with the latest version of kfmtbox
|
||||
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: GitHub Community Support
|
||||
url: https://github.com/yourusername/kfmtbox/discussions
|
||||
about: Please ask and answer questions here.
|
||||
- name: Documentation
|
||||
url: https://github.com/yourusername/kfmtbox/wiki
|
||||
about: Check our documentation for detailed guides and examples.
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for kfmtbox
|
||||
title: '[FEATURE] '
|
||||
labels: ['enhancement', 'needs-triage']
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## 🚀 Feature Description
|
||||
|
||||
A clear and concise description of the feature you'd like to see implemented.
|
||||
|
||||
## 💡 Motivation
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
## 🎯 Proposed Solution
|
||||
|
||||
Describe the solution you'd like to see implemented.
|
||||
|
||||
## 🔄 Alternative Solutions
|
||||
|
||||
Describe any alternative solutions or features you've considered.
|
||||
|
||||
## 📋 Use Cases
|
||||
|
||||
Provide specific examples of how this feature would be used:
|
||||
|
||||
```bash
|
||||
# Example usage
|
||||
echo "text" | kfmtbox --new-flag
|
||||
```
|
||||
|
||||
## 🎨 Design Considerations
|
||||
|
||||
If this feature involves UI changes, please describe:
|
||||
- How should it look?
|
||||
- What should the user experience be?
|
||||
- Any specific design requirements?
|
||||
|
||||
## 🔧 Implementation Notes
|
||||
|
||||
If you have ideas about how this could be implemented, please share them.
|
||||
|
||||
## 📚 Additional Context
|
||||
|
||||
Add any other context, mockups, or examples about the feature request here.
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
- [ ] I have searched existing issues to ensure this is not a duplicate
|
||||
- [ ] I have provided all the information requested above
|
||||
- [ ] This feature would be useful to other users
|
||||
- [ ] I am willing to help implement this feature if needed
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question about kfmtbox
|
||||
title: '[QUESTION] '
|
||||
labels: ['question', 'needs-triage']
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## ❓ Question
|
||||
|
||||
What would you like to know about kfmtbox?
|
||||
|
||||
## 🔍 What I've Tried
|
||||
|
||||
Describe what you've already tried or researched:
|
||||
|
||||
- [ ] Checked the README
|
||||
- [ ] Searched existing issues
|
||||
- [ ] Looked at the documentation
|
||||
- [ ] Tried different approaches
|
||||
|
||||
## 💻 Environment
|
||||
|
||||
**OS:** [e.g. macOS 13.0, Ubuntu 22.04, Windows 11]
|
||||
**Rust version:** [e.g. 1.70.0]
|
||||
**kfmtbox version:** [e.g. 0.1.0]
|
||||
|
||||
## 📝 Example
|
||||
|
||||
If applicable, provide a code example or command that relates to your question:
|
||||
|
||||
```bash
|
||||
# Your example here
|
||||
echo "text" | kfmtbox --filetype rs
|
||||
```
|
||||
|
||||
## 🎯 Expected Outcome
|
||||
|
||||
What would you like to achieve or understand?
|
||||
|
||||
## 📚 Additional Context
|
||||
|
||||
Add any other context, screenshots, or examples that might help answer your question.
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
- [ ] I have searched existing issues and discussions
|
||||
- [ ] I have provided all relevant information
|
||||
- [ ] My question is specific and clear
|
||||
@@ -0,0 +1,105 @@
|
||||
## 📋 Pull Request Description
|
||||
|
||||
<!-- Provide a brief description of the changes in this PR -->
|
||||
|
||||
## 🔗 Related Issues
|
||||
|
||||
<!-- Link to any related issues -->
|
||||
- Closes #(issue number)
|
||||
- Related to #(issue number)
|
||||
|
||||
## 🎯 Type of Change
|
||||
|
||||
<!-- Mark the relevant option with an "x" -->
|
||||
|
||||
- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] ✨ New feature (non-breaking change which adds functionality)
|
||||
- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] 📚 Documentation update
|
||||
- [ ] 🧪 Test improvements
|
||||
- [ ] 🔧 Refactoring (no functional changes)
|
||||
- [ ] ⚡ Performance improvement
|
||||
- [ ] 🔒 Security fix
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
<!-- Describe the tests you ran to verify your changes -->
|
||||
|
||||
- [ ] Unit tests pass
|
||||
- [ ] Integration tests pass
|
||||
- [ ] Manual testing completed
|
||||
- [ ] Tested on multiple platforms (if applicable)
|
||||
|
||||
### Test Commands
|
||||
|
||||
```bash
|
||||
# Add any specific test commands you ran
|
||||
cargo test
|
||||
cargo clippy
|
||||
cargo fmt
|
||||
```
|
||||
|
||||
## 📸 Screenshots/Examples
|
||||
|
||||
<!-- If applicable, add screenshots or examples of the changes -->
|
||||
|
||||
### Before
|
||||
```bash
|
||||
# Example of behavior before changes
|
||||
```
|
||||
|
||||
### After
|
||||
```bash
|
||||
# Example of behavior after changes
|
||||
```
|
||||
|
||||
## 🔍 Code Quality
|
||||
|
||||
<!-- Mark completed items with an "x" -->
|
||||
|
||||
- [ ] Code follows project style guidelines
|
||||
- [ ] Self-review completed
|
||||
- [ ] Code is properly commented
|
||||
- [ ] No unnecessary debug code or comments
|
||||
- [ ] Error handling is appropriate
|
||||
- [ ] Performance implications considered
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
<!-- Mark completed items with an "x" -->
|
||||
|
||||
- [ ] README updated (if needed)
|
||||
- [ ] Code comments added/updated
|
||||
- [ ] API documentation updated (if applicable)
|
||||
- [ ] Examples updated (if applicable)
|
||||
|
||||
## 🚀 Deployment Notes
|
||||
|
||||
<!-- Any special deployment considerations -->
|
||||
|
||||
- [ ] No breaking changes
|
||||
- [ ] Backward compatibility maintained
|
||||
- [ ] Migration guide needed (if breaking changes)
|
||||
- [ ] Configuration changes documented
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
<!-- Mark completed items with an "x" -->
|
||||
|
||||
- [ ] My code follows the style guidelines of this project
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have made corresponding changes to the documentation
|
||||
- [ ] My changes generate no new warnings
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] New and existing unit tests pass locally with my changes
|
||||
- [ ] Any dependent changes have been merged and published
|
||||
|
||||
## 🔄 Additional Notes
|
||||
|
||||
<!-- Any additional information that reviewers should know -->
|
||||
|
||||
## 👥 Reviewers
|
||||
|
||||
<!-- Tag specific reviewers if needed -->
|
||||
@username
|
||||
@@ -0,0 +1,114 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust: [stable, beta, nightly]
|
||||
include:
|
||||
- rust: stable
|
||||
cache-key: stable
|
||||
- rust: beta
|
||||
cache-key: beta
|
||||
- rust: nightly
|
||||
cache-key: nightly
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ runner.os }}-cargo-registry-${{ matrix.cache-key }}
|
||||
|
||||
- name: Cache cargo index
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-index-${{ matrix.cache-key }}
|
||||
|
||||
- name: Cache cargo build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target
|
||||
key: ${{ runner.os }}-cargo-build-target-${{ matrix.cache-key }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Install cargo-cache
|
||||
run: cargo install cargo-cache
|
||||
|
||||
- name: Cache cargo
|
||||
run: cargo cache -a
|
||||
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-targets --all-features -- -D warnings
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
security:
|
||||
name: Security Audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install cargo-audit
|
||||
run: cargo install cargo-audit
|
||||
|
||||
- name: Run security audit
|
||||
run: cargo audit
|
||||
|
||||
build:
|
||||
name: Build Release
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [test, security]
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build release
|
||||
run: cargo build --release --verbose
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: kfmtbox-${{ matrix.os }}
|
||||
path: target/release/kfmtbox*
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Dependabot Auto-merge
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
jobs:
|
||||
dependabot:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
steps:
|
||||
- name: Dependabot metadata
|
||||
id: metadata
|
||||
uses: dependabot/fetch-metadata@v1
|
||||
with:
|
||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
- name: Enable auto-merge for Dependabot PRs
|
||||
if: steps.metadata.outputs.update-type == 'version-update:semver-patch'
|
||||
run: gh pr merge --auto --merge "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{github.event.pull_request.html_url}}
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
@@ -0,0 +1,115 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
create-release:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
build:
|
||||
needs: create-release
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
asset_name: kfmtbox-linux-x86_64
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-musl
|
||||
asset_name: kfmtbox-linux-x86_64-musl
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
asset_name: kfmtbox-macos-x86_64
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
asset_name: kfmtbox-macos-aarch64
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
asset_name: kfmtbox-windows-x86_64.exe
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-gnu
|
||||
asset_name: kfmtbox-windows-x86_64-gnu.exe
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Build
|
||||
run: cargo build --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Strip binary (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
run: strip target/${{ matrix.target }}/release/kfmtbox
|
||||
|
||||
- name: Upload Release Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.create-release.outputs.upload_url }}
|
||||
asset_path: target/${{ matrix.target }}/release/kfmtbox${{ matrix.target == 'x86_64-pc-windows-msvc' && '.exe' || matrix.target == 'x86_64-pc-windows-gnu' && '.exe' || '' }}
|
||||
asset_name: ${{ matrix.asset_name }}
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
publish-crate:
|
||||
needs: create-release
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'koftwentytwo' # Only publish from the main repository
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Publish to crates.io
|
||||
run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
update-homebrew:
|
||||
needs: [create-release, build]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'koftwentytwo' # Only update from the main repository
|
||||
steps:
|
||||
- name: Checkout homebrew-core
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: Homebrew/homebrew-core
|
||||
token: ${{ secrets.HOMEBREW_CORE_TOKEN }}
|
||||
path: homebrew-core
|
||||
|
||||
- name: Update formula
|
||||
run: |
|
||||
# This would typically be done via a PR to homebrew-core
|
||||
# For now, we'll just prepare the formula
|
||||
echo "Formula update would go here"
|
||||
echo "See: https://docs.brew.sh/Adding-Software-to-Homebrew"
|
||||
+66
-17
@@ -1,21 +1,70 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug
|
||||
target
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
# Rust
|
||||
/target/
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Generated by cargo mutants
|
||||
# Contains mutation testing data
|
||||
**/mutants.out*/
|
||||
# OS
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# RustRover
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage/
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# Temporary folders
|
||||
tmp/
|
||||
temp/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# Local configuration files
|
||||
config.local.yaml
|
||||
config.local.yml
|
||||
@@ -0,0 +1,13 @@
|
||||
# KofTwentyTwo rustfmt configuration (K22-CODE-RS). Stable-channel options only, so
|
||||
# `cargo fmt --check` behaves the same on every toolchain.
|
||||
edition = "2021"
|
||||
# Kingsrook: 3-space indentation (tab_spaces is a stable option).
|
||||
tab_spaces = 3
|
||||
hard_tabs = false
|
||||
newline_style = "Unix"
|
||||
# Kingsrook: no practical line limit. 200 keeps rustfmt's wrapping heuristics sane.
|
||||
max_width = 200
|
||||
use_field_init_shorthand = true
|
||||
use_try_shorthand = true
|
||||
# Not set: brace_style = "AlwaysNextLine" and blank_lines_upper_bound are nightly-only.
|
||||
# Rust therefore keeps rustfmt's same-line braces (profile rule K22-CODE-RS-02).
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Initial release of kfmtbox
|
||||
- Support for flower box comment formatting
|
||||
- File type detection from filename and explicit filetype
|
||||
- Text wrapping with balanced line lengths
|
||||
- Existing comment detection and reformatting
|
||||
- YAML configuration support for custom comment styles
|
||||
- Support for 25+ programming languages
|
||||
- CLI interface with comprehensive options
|
||||
- Unit tests for core functionality
|
||||
- GitHub Actions CI/CD pipeline
|
||||
- Comprehensive documentation
|
||||
|
||||
### Features
|
||||
- Beautiful Unicode box drawing characters (╭╮╰╯│─)
|
||||
- Smart text wrapping with configurable max width
|
||||
- Automatic comment style detection
|
||||
- Configuration file support
|
||||
- Editor integration examples
|
||||
- Cross-platform support (Linux, macOS, Windows)
|
||||
|
||||
## [0.1.0] - 2024-09-01
|
||||
|
||||
### Added
|
||||
- Initial release
|
||||
- Core flower box rendering functionality
|
||||
- File type detection system
|
||||
- Text wrapping and balancing
|
||||
- YAML configuration support
|
||||
- CLI argument parsing with clap
|
||||
- Comprehensive test suite
|
||||
- Documentation and examples
|
||||
|
||||
### Supported File Types
|
||||
- Rust (.rs) → //
|
||||
- Python (.py) → #
|
||||
- JavaScript (.js) → //
|
||||
- TypeScript (.ts) → //
|
||||
- Go (.go) → //
|
||||
- Java (.java) → //
|
||||
- C/C++ (.c, .cpp, .h, .hpp) → //
|
||||
- C# (.cs) → //
|
||||
- PHP (.php) → //
|
||||
- Ruby (.rb) → #
|
||||
- Shell (.sh, .bash, .zsh, .fish) → #
|
||||
- Vim (.vim) → "
|
||||
- Lua (.lua) → --
|
||||
- SQL (.sql) → --
|
||||
- YAML (.yaml, .yml) → #
|
||||
- TOML (.toml) → #
|
||||
- INI (.ini, .cfg) → ;
|
||||
- Dockerfile → #
|
||||
- Makefile → #
|
||||
- CMake (CMakeLists.txt) → #
|
||||
|
||||
### CLI Options
|
||||
- `-f, --filename` - Input filename for file type detection
|
||||
- `-t, --filetype` - File type for comment style detection
|
||||
- `-w, --max-width` - Maximum line width (default: 120)
|
||||
- `-h, --help` - Print help information
|
||||
- `-V, --version` - Print version information
|
||||
|
||||
### Configuration
|
||||
- YAML configuration file support
|
||||
- Custom comment style definitions
|
||||
- Platform-specific config locations
|
||||
- Default fallback comment styles
|
||||
|
||||
### Testing
|
||||
- Unit tests for all core modules
|
||||
- Integration tests for CLI functionality
|
||||
- Text wrapping and balancing tests
|
||||
- Comment detection and extraction tests
|
||||
- Cross-platform compatibility testing
|
||||
|
||||
### Documentation
|
||||
- Comprehensive README with examples
|
||||
- Contributing guidelines
|
||||
- Code of conduct
|
||||
- Security policy
|
||||
- API documentation
|
||||
- Editor integration examples
|
||||
|
||||
---
|
||||
|
||||
## Version Numbering
|
||||
|
||||
This project uses [Semantic Versioning](https://semver.org/):
|
||||
|
||||
- **MAJOR** version when you make incompatible API changes
|
||||
- **MINOR** version when you add functionality in a backwards compatible manner
|
||||
- **PATCH** version when you make backwards compatible bug fixes
|
||||
|
||||
## Types of Changes
|
||||
|
||||
- **Added** for new features
|
||||
- **Changed** for changes in existing functionality
|
||||
- **Deprecated** for soon-to-be removed features
|
||||
- **Removed** for now removed features
|
||||
- **Fixed** for any bug fixes
|
||||
- **Security** for vulnerability fixes
|
||||
@@ -0,0 +1,122 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[INSERT CONTACT METHOD]. All complaints will be reviewed and investigated
|
||||
promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
# Contributing to kfmtbox
|
||||
|
||||
Thank you for your interest in contributing to kfmtbox! This document provides guidelines and information for contributors.
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Rust 1.70+ (edition 2021)
|
||||
- Cargo
|
||||
- Git
|
||||
|
||||
### Development Setup
|
||||
|
||||
1. **Fork and clone the repository**
|
||||
```bash
|
||||
git clone https://github.com/yourusername/kfmtbox.git
|
||||
cd kfmtbox
|
||||
```
|
||||
|
||||
2. **Build the project**
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
|
||||
3. **Run tests**
|
||||
```bash
|
||||
cargo test
|
||||
```
|
||||
|
||||
4. **Check code quality**
|
||||
```bash
|
||||
cargo clippy
|
||||
cargo fmt
|
||||
```
|
||||
|
||||
## 🎯 How to Contribute
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
Before creating a bug report, please check existing issues to avoid duplicates. When creating a bug report, include:
|
||||
|
||||
- **Clear description** of the bug
|
||||
- **Steps to reproduce** the issue
|
||||
- **Expected behavior** vs actual behavior
|
||||
- **Environment details** (OS, Rust version, etc.)
|
||||
- **Sample input** that triggers the bug (if applicable)
|
||||
|
||||
Use the [bug report template](.github/ISSUE_TEMPLATE/bug_report.md) when creating issues.
|
||||
|
||||
### Suggesting Features
|
||||
|
||||
We welcome feature suggestions! When proposing a new feature:
|
||||
|
||||
- **Describe the problem** it solves
|
||||
- **Explain the proposed solution**
|
||||
- **Consider alternatives** you've thought about
|
||||
- **Provide examples** of how it would work
|
||||
|
||||
Use the [feature request template](.github/ISSUE_TEMPLATE/feature_request.md) when creating issues.
|
||||
|
||||
### Code Contributions
|
||||
|
||||
#### Development Workflow
|
||||
|
||||
1. **Create a feature branch**
|
||||
```bash
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
|
||||
2. **Make your changes**
|
||||
- Write clean, well-documented code
|
||||
- Follow Rust naming conventions
|
||||
- Add tests for new functionality
|
||||
- Update documentation as needed
|
||||
|
||||
3. **Test your changes**
|
||||
```bash
|
||||
cargo test
|
||||
cargo clippy
|
||||
cargo fmt
|
||||
```
|
||||
|
||||
4. **Commit your changes**
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Add: brief description of changes"
|
||||
```
|
||||
|
||||
5. **Push and create a Pull Request**
|
||||
```bash
|
||||
git push origin feature/your-feature-name
|
||||
```
|
||||
|
||||
#### Code Style Guidelines
|
||||
|
||||
- **Formatting**: Use `cargo fmt` to format code
|
||||
- **Linting**: Address all `cargo clippy` warnings
|
||||
- **Documentation**: Document public APIs with doc comments
|
||||
- **Tests**: Write unit tests for new functionality
|
||||
- **Naming**: Follow Rust naming conventions (snake_case for functions/variables, PascalCase for types)
|
||||
|
||||
#### Commit Message Format
|
||||
|
||||
Use clear, descriptive commit messages:
|
||||
|
||||
```
|
||||
Add: support for block comments in C/C++ files
|
||||
Fix: text wrapping edge case with Unicode characters
|
||||
Update: improve error messages for invalid file types
|
||||
Docs: add examples for VSCode integration
|
||||
Test: add unit tests for comment detection logic
|
||||
```
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
cargo test
|
||||
|
||||
# Run tests with output
|
||||
cargo test -- --nocapture
|
||||
|
||||
# Run specific test
|
||||
cargo test test_name
|
||||
|
||||
# Run integration tests
|
||||
cargo test --test integration_tests
|
||||
```
|
||||
|
||||
### Writing Tests
|
||||
|
||||
- **Unit tests**: Place in the same file as the code being tested
|
||||
- **Integration tests**: Place in `tests/` directory
|
||||
- **Test coverage**: Aim for good test coverage of new functionality
|
||||
- **Edge cases**: Test edge cases and error conditions
|
||||
|
||||
### Test Examples
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_comment_detection() {
|
||||
let detector = CommentDetector::new();
|
||||
let style = detector.detect_from_filetype("rs");
|
||||
assert_eq!(style.prefix, "//");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_text_wrapping() {
|
||||
let wrapper = TextWrapper::new(20);
|
||||
let result = wrapper.wrap_text("This is a very long line");
|
||||
assert!(result.len() > 1);
|
||||
for line in &result {
|
||||
assert!(line.len() <= 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
kfmtbox/
|
||||
├── src/
|
||||
│ ├── main.rs # CLI entry point
|
||||
│ ├── lib.rs # Library exports
|
||||
│ ├── cli.rs # Command line parsing
|
||||
│ ├── box_renderer.rs # Flower box rendering
|
||||
│ ├── text_wrapper.rs # Text wrapping logic
|
||||
│ ├── comment_detector.rs # File type detection
|
||||
│ └── config.rs # Configuration handling
|
||||
├── tests/ # Integration tests
|
||||
├── .github/ # GitHub workflows and templates
|
||||
├── Cargo.toml # Project configuration
|
||||
├── README.md # Project documentation
|
||||
├── CONTRIBUTING.md # This file
|
||||
└── LICENSE # MIT License
|
||||
```
|
||||
|
||||
## 🔍 Code Review Process
|
||||
|
||||
### Pull Request Guidelines
|
||||
|
||||
- **Clear description** of changes and motivation
|
||||
- **Link to related issues** if applicable
|
||||
- **Screenshots or examples** for UI changes
|
||||
- **Update documentation** as needed
|
||||
- **Ensure all tests pass**
|
||||
|
||||
### Review Checklist
|
||||
|
||||
- [ ] Code follows project style guidelines
|
||||
- [ ] Tests are included and passing
|
||||
- [ ] Documentation is updated
|
||||
- [ ] No breaking changes (or clearly documented)
|
||||
- [ ] Performance implications considered
|
||||
- [ ] Security implications reviewed
|
||||
|
||||
## 🐛 Common Issues and Solutions
|
||||
|
||||
### Build Issues
|
||||
|
||||
**Problem**: `cargo build` fails with dependency errors
|
||||
**Solution**: Run `cargo update` to update dependencies
|
||||
|
||||
**Problem**: Tests fail on specific platforms
|
||||
**Solution**: Check if the issue is platform-specific and add appropriate test conditions
|
||||
|
||||
### Code Issues
|
||||
|
||||
**Problem**: Clippy warnings
|
||||
**Solution**: Address all warnings or add `#[allow(clippy::warning_name)]` with justification
|
||||
|
||||
**Problem**: Formatting issues
|
||||
**Solution**: Run `cargo fmt` to auto-format code
|
||||
|
||||
## 📚 Resources
|
||||
|
||||
- [Rust Book](https://doc.rust-lang.org/book/)
|
||||
- [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/)
|
||||
- [Clap Documentation](https://docs.rs/clap/)
|
||||
- [Serde Documentation](https://serde.rs/)
|
||||
|
||||
## 💬 Getting Help
|
||||
|
||||
- **GitHub Discussions**: For questions and general discussion
|
||||
- **GitHub Issues**: For bug reports and feature requests
|
||||
- **Pull Request Comments**: For code review discussions
|
||||
|
||||
## 🎉 Recognition
|
||||
|
||||
Contributors will be recognized in:
|
||||
- README.md contributors section
|
||||
- Release notes for significant contributions
|
||||
- GitHub contributor graph
|
||||
|
||||
Thank you for contributing to kfmtbox! 🚀
|
||||
Generated
+344
@@ -0,0 +1,344 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "kfmtbox"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"dirs",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.191"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0"
|
||||
dependencies = [
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
[package]
|
||||
name = "kfmtbox"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["James Maes <james@kof22.com>"]
|
||||
description = "A Rust-based command-line utility that wraps text in flower box style comments"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/koftwentytwo/kfmtbox"
|
||||
homepage = "https://github.com/koftwentytwo/kfmtbox"
|
||||
documentation = "https://docs.rs/kfmtbox"
|
||||
readme = "README.md"
|
||||
keywords = ["cli", "formatting", "comments", "text-processing", "code-formatter"]
|
||||
categories = ["command-line-utilities", "text-processing", "development-tools::build-utils"]
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.4", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_yaml = "0.9"
|
||||
dirs = "6.0.0"
|
||||
|
||||
[[bin]]
|
||||
name = "kfmtbox"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
# Linting configuration
|
||||
[lints.clippy]
|
||||
# Based on your .clang-tidy preferences
|
||||
# Be strict about code quality and style
|
||||
all = { level = "warn", priority = -1 }
|
||||
pedantic = { level = "warn", priority = -1 }
|
||||
nursery = { level = "warn", priority = -1 }
|
||||
cargo = { level = "warn", priority = -1 }
|
||||
|
||||
# Disable some lints that might be too noisy
|
||||
# (equivalent to disabling some checks in clang-tidy)
|
||||
missing-docs-in-private-items = "allow"
|
||||
module-name-repetitions = "allow"
|
||||
|
||||
# Keep explicit return statements (disable needless-return warnings)
|
||||
needless-return = "allow"
|
||||
redundant-else = "allow"
|
||||
question-mark-used = "allow"
|
||||
|
||||
# Enable strict style checks (similar to readability-braces-around-statements)
|
||||
needless-lifetimes = "warn"
|
||||
redundant-closure = "warn"
|
||||
unnecessary-lazy-evaluations = "warn"
|
||||
|
||||
# Performance and safety checks
|
||||
unwrap-used = "warn"
|
||||
expect-used = "warn"
|
||||
panic = "warn"
|
||||
unreachable = "warn"
|
||||
|
||||
# Complexity checks (similar to your C++ style preferences)
|
||||
too-many-arguments = "warn"
|
||||
too-many-lines = "warn"
|
||||
cognitive-complexity = "warn"
|
||||
|
||||
# Type safety checks
|
||||
cast-precision-loss = "warn"
|
||||
cast-possible-truncation = "warn"
|
||||
float-arithmetic = "warn"
|
||||
|
||||
# Memory and performance checks
|
||||
large-enum-variant = "warn"
|
||||
large-stack-arrays = "warn"
|
||||
|
||||
# String and collection checks
|
||||
string-slice = "warn"
|
||||
collection-is-never-read = "warn"
|
||||
indexing-slicing = "warn"
|
||||
|
||||
# Async and concurrency checks
|
||||
async-yields-async = "warn"
|
||||
await-holding-lock = "warn"
|
||||
|
||||
# Documentation and naming
|
||||
doc-markdown = "warn"
|
||||
|
||||
# Error handling
|
||||
result-large-err = "warn"
|
||||
missing-errors-doc = "warn"
|
||||
|
||||
# Macro usage
|
||||
redundant-pattern-matching = "warn"
|
||||
|
||||
# Integer arithmetic
|
||||
arithmetic-side-effects = "warn"
|
||||
integer-division = "warn"
|
||||
|
||||
# Additional strict checks
|
||||
implicit-return = "warn"
|
||||
single-match-else = "warn"
|
||||
@@ -0,0 +1,25 @@
|
||||
class Kfmtbox < Formula
|
||||
desc "A Rust-based command-line utility that wraps text in flower box style comments"
|
||||
homepage "https://github.com/koftwentytwo/kfmtbox"
|
||||
url "https://github.com/koftwentytwo/kfmtbox/archive/v0.1.0.tar.gz"
|
||||
sha256 "" # This will be filled in after the first release
|
||||
license "MIT"
|
||||
head "https://github.com/koftwentytwo/kfmtbox.git", branch: "main"
|
||||
|
||||
depends_on "rust" => :build
|
||||
|
||||
def install
|
||||
system "cargo", "install", *std_cargo_args
|
||||
end
|
||||
|
||||
test do
|
||||
# Test basic functionality
|
||||
assert_match "kfmtbox", shell_output("#{bin}/kfmtbox --help")
|
||||
|
||||
# Test with a simple input
|
||||
test_input = "Hello, world!"
|
||||
expected_output = shell_output("echo '#{test_input}' | #{bin}/kfmtbox --filetype rs")
|
||||
assert_match "╭", expected_output
|
||||
assert_match "Hello, world!", expected_output
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 James Maes
|
||||
Copyright (c) 2024 kfmtbox contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
# Package Distribution Guide
|
||||
|
||||
This document explains how to distribute `kfmtbox` through various package managers and platforms.
|
||||
|
||||
## 📦 Package Managers
|
||||
|
||||
### 1. Homebrew (macOS/Linux)
|
||||
|
||||
#### Option A: Personal Tap (Recommended for initial release)
|
||||
1. Create a personal tap repository: `koftwentytwo/homebrew-kfmtbox`
|
||||
2. Add the formula from `Formula/kfmtbox.rb` to your tap
|
||||
3. Users can install with:
|
||||
```bash
|
||||
brew tap koftwentytwo/kfmtbox
|
||||
brew install kfmtbox
|
||||
```
|
||||
|
||||
#### Option B: Homebrew Core (For wider distribution)
|
||||
1. Submit a PR to [homebrew-core](https://github.com/Homebrew/homebrew-core)
|
||||
2. Follow the [Homebrew formula guidelines](https://docs.brew.sh/Formula-Cookbook)
|
||||
3. Requirements:
|
||||
- At least 20 stars on GitHub
|
||||
- At least 3 months old
|
||||
- Stable API
|
||||
- No dependencies on non-free software
|
||||
|
||||
### 2. Cargo (Rust)
|
||||
|
||||
#### Prerequisites
|
||||
1. Create account on [crates.io](https://crates.io)
|
||||
2. Get API token from account settings
|
||||
3. Add token to GitHub secrets as `CARGO_REGISTRY_TOKEN`
|
||||
|
||||
#### Publishing
|
||||
```bash
|
||||
# Login to crates.io
|
||||
cargo login
|
||||
|
||||
# Publish (done automatically via GitHub Actions)
|
||||
cargo publish
|
||||
```
|
||||
|
||||
### 3. Arch Linux (AUR)
|
||||
|
||||
Create a PKGBUILD file:
|
||||
|
||||
```bash
|
||||
# Create AUR package
|
||||
git clone ssh://aur@aur.archlinux.org/kfmtbox.git
|
||||
cd kfmtbox
|
||||
|
||||
# Add PKGBUILD (see below)
|
||||
git add PKGBUILD .SRCINFO
|
||||
git commit -m "Initial release"
|
||||
git push
|
||||
```
|
||||
|
||||
**PKGBUILD template:**
|
||||
```bash
|
||||
pkgname=kfmtbox
|
||||
pkgver=0.1.0
|
||||
pkgrel=1
|
||||
pkgdesc="A Rust-based command-line utility that wraps text in flower box style comments"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/koftwentytwo/kfmtbox"
|
||||
license=('MIT')
|
||||
depends=('glibc')
|
||||
makedepends=('cargo' 'git')
|
||||
source=("$pkgname-$pkgver.tar.gz::https://github.com/koftwentytwo/kfmtbox/archive/v$pkgver.tar.gz")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
build() {
|
||||
cd "$pkgname-$pkgver"
|
||||
cargo build --release --locked
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$pkgname-$pkgver"
|
||||
install -Dm755 "target/release/$pkgname" "$pkgdir/usr/bin/$pkgname"
|
||||
install -Dm644 "README.md" "$pkgdir/usr/share/doc/$pkgname/README.md"
|
||||
install -Dm644 "LICENSE" "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Debian/Ubuntu (PPA)
|
||||
|
||||
#### Prerequisites
|
||||
1. Create Launchpad account
|
||||
2. Set up PPA
|
||||
3. Install packaging tools: `sudo apt install devscripts debhelper`
|
||||
|
||||
#### Creating Debian Package
|
||||
```bash
|
||||
# Create package structure
|
||||
mkdir kfmtbox-0.1.0
|
||||
cd kfmtbox-0.1.0
|
||||
|
||||
# Copy source files
|
||||
cp -r ../src .
|
||||
cp ../Cargo.toml ../Cargo.lock .
|
||||
|
||||
# Create debian directory
|
||||
mkdir debian
|
||||
|
||||
# Add control file, rules, etc.
|
||||
# (See Debian packaging documentation)
|
||||
```
|
||||
|
||||
### 5. Windows (Chocolatey)
|
||||
|
||||
#### Prerequisites
|
||||
1. Create Chocolatey account
|
||||
2. Install Chocolatey package validator
|
||||
|
||||
#### Package Structure
|
||||
```
|
||||
kfmtbox/
|
||||
├── kfmtbox.nuspec
|
||||
├── tools/
|
||||
│ ├── chocolateyinstall.ps1
|
||||
│ └── chocolateyuninstall.ps1
|
||||
└── legal/
|
||||
└── LICENSE.txt
|
||||
```
|
||||
|
||||
**kfmtbox.nuspec:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>kfmtbox</id>
|
||||
<version>0.1.0</version>
|
||||
<title>kfmtbox</title>
|
||||
<authors>James Maes</authors>
|
||||
<description>A Rust-based command-line utility that wraps text in flower box style comments</description>
|
||||
<licenseUrl>https://github.com/koftwentytwo/kfmtbox/blob/main/LICENSE</licenseUrl>
|
||||
<projectUrl>https://github.com/koftwentytwo/kfmtbox</projectUrl>
|
||||
<tags>cli formatting comments text-processing</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="tools\**" target="tools" />
|
||||
<file src="legal\**" target="legal" />
|
||||
</files>
|
||||
</package>
|
||||
```
|
||||
|
||||
### 6. Snap (Ubuntu/Snap Store)
|
||||
|
||||
#### Prerequisites
|
||||
1. Create Snapcraft account
|
||||
2. Install snapcraft: `sudo snap install snapcraft --classic`
|
||||
|
||||
#### snapcraft.yaml
|
||||
```yaml
|
||||
name: kfmtbox
|
||||
version: '0.1.0'
|
||||
summary: A Rust-based command-line utility that wraps text in flower box style comments
|
||||
description: |
|
||||
Transform your plain text into beautiful, decorative comment boxes that automatically
|
||||
adapt to your programming language's comment syntax.
|
||||
|
||||
grade: stable
|
||||
confinement: strict
|
||||
|
||||
parts:
|
||||
kfmtbox:
|
||||
plugin: rust
|
||||
source: .
|
||||
build-packages:
|
||||
- gcc
|
||||
- pkg-config
|
||||
- libssl-dev
|
||||
|
||||
apps:
|
||||
kfmtbox:
|
||||
command: kfmtbox
|
||||
plugs:
|
||||
- home
|
||||
```
|
||||
|
||||
## 🚀 Release Process
|
||||
|
||||
### 1. Automated Releases (GitHub Actions)
|
||||
|
||||
The project includes automated release workflows that:
|
||||
|
||||
1. **Build binaries** for multiple platforms:
|
||||
- Linux (x86_64, musl)
|
||||
- macOS (x86_64, ARM64)
|
||||
- Windows (x86_64, MSVC and GNU)
|
||||
|
||||
2. **Publish to crates.io** (when `CARGO_REGISTRY_TOKEN` is set)
|
||||
|
||||
3. **Create GitHub releases** with downloadable binaries
|
||||
|
||||
### 2. Manual Release Steps
|
||||
|
||||
1. **Update version** in `Cargo.toml`
|
||||
2. **Create git tag**: `git tag v0.1.0`
|
||||
3. **Push tag**: `git push origin v0.1.0`
|
||||
4. **GitHub Actions** will automatically:
|
||||
- Build and test
|
||||
- Create release
|
||||
- Upload binaries
|
||||
- Publish to crates.io (if configured)
|
||||
|
||||
### 3. Package Manager Updates
|
||||
|
||||
After each release, update package managers:
|
||||
|
||||
1. **Homebrew**: Update formula with new version and SHA
|
||||
2. **AUR**: Update PKGBUILD with new version
|
||||
3. **Snap**: Update snapcraft.yaml version
|
||||
4. **Chocolatey**: Update nuspec version
|
||||
|
||||
## 📋 Checklist for New Release
|
||||
|
||||
- [ ] Update version in `Cargo.toml`
|
||||
- [ ] Update `CHANGELOG.md`
|
||||
- [ ] Create and push git tag
|
||||
- [ ] Verify GitHub Actions release
|
||||
- [ ] Update Homebrew formula (if using personal tap)
|
||||
- [ ] Update AUR package
|
||||
- [ ] Update other package managers
|
||||
- [ ] Test installation from all package managers
|
||||
- [ ] Update documentation
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Homebrew formula fails**: Check SHA256 hash and URL
|
||||
2. **Cargo publish fails**: Verify API token and package name availability
|
||||
3. **AUR package rejected**: Check PKGBUILD syntax and dependencies
|
||||
4. **Snap build fails**: Verify snapcraft.yaml syntax
|
||||
|
||||
### Getting Help
|
||||
|
||||
- [Homebrew Formula Cookbook](https://docs.brew.sh/Formula-Cookbook)
|
||||
- [Cargo Publishing Guide](https://doc.rust-lang.org/cargo/reference/publishing.html)
|
||||
- [AUR User Guidelines](https://wiki.archlinux.org/title/AUR_user_guidelines)
|
||||
- [Snapcraft Documentation](https://snapcraft.io/docs)
|
||||
|
||||
## 📊 Distribution Statistics
|
||||
|
||||
Track your package downloads and usage:
|
||||
|
||||
- **Crates.io**: [crates.io/crates/kfmtbox](https://crates.io/crates/kfmtbox)
|
||||
- **Homebrew**: `brew info kfmtbox`
|
||||
- **GitHub**: Release download statistics
|
||||
- **AUR**: AUR package page statistics
|
||||
@@ -1,2 +1,333 @@
|
||||
# kfmtbox
|
||||
A Rust-based command-line utility that wraps one or more lines of text in a “flower box” style comment, using the appropriate comment style for the file type.
|
||||
# kfmtbox 🌸
|
||||
|
||||
> A beautiful Rust CLI tool that wraps your text in elegant flower box comments
|
||||
|
||||
[](https://crates.io/crates/kfmtbox)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://github.com/koftwentytwo/kfmtbox/actions)
|
||||
|
||||
Transform your plain text into beautiful, decorative comment boxes that automatically adapt to your programming language's comment syntax.
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- 🎨 **Beautiful Unicode box drawing** with perfect rectangular formatting
|
||||
- 🔍 **Smart file type detection** from filename or explicit specification
|
||||
- 📝 **Intelligent text wrapping** with balanced line lengths
|
||||
- 🔄 **Existing comment detection** - reformats existing flower boxes
|
||||
- ⚙️ **YAML configuration** for custom comment styles
|
||||
- 🚀 **Editor integration** ready for Neovim, VSCode, and more
|
||||
- 🦀 **Written in Rust** - fast, reliable, and memory-safe
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Installation
|
||||
|
||||
#### 🚀 One-Line Install (Recommended)
|
||||
```bash
|
||||
# Linux/macOS
|
||||
curl -sSL https://raw.githubusercontent.com/koftwentytwo/kfmtbox/main/install.sh | bash
|
||||
|
||||
# Windows PowerShell
|
||||
powershell -ExecutionPolicy Bypass -File <(curl -sSL https://raw.githubusercontent.com/koftwentytwo/kfmtbox/main/install.ps1)
|
||||
```
|
||||
|
||||
#### 📦 Package Managers
|
||||
|
||||
**Homebrew (macOS/Linux)**
|
||||
```bash
|
||||
# Add the tap (after first release)
|
||||
brew tap koftwentytwo/kfmtbox
|
||||
brew install kfmtbox
|
||||
|
||||
# Or install directly from formula
|
||||
brew install koftwentytwo/kfmtbox/kfmtbox
|
||||
```
|
||||
|
||||
**Cargo (Rust)**
|
||||
```bash
|
||||
cargo install kfmtbox
|
||||
```
|
||||
|
||||
**Arch Linux (AUR)**
|
||||
```bash
|
||||
# After AUR package is created
|
||||
yay -S kfmtbox
|
||||
```
|
||||
|
||||
#### 🔨 From Source
|
||||
```bash
|
||||
git clone https://github.com/koftwentytwo/kfmtbox.git
|
||||
cd kfmtbox
|
||||
cargo build --release
|
||||
sudo cp target/release/kfmtbox /usr/local/bin/
|
||||
```
|
||||
|
||||
#### 📥 Manual Download
|
||||
Visit the [Releases](https://github.com/koftwentytwo/kfmtbox/releases) page to download pre-built binaries for your platform.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
echo "Hello, world!" | kfmtbox --filetype rs
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
// ╭───────────────╮
|
||||
// │Hello, world! │
|
||||
// ╰───────────────╯
|
||||
```
|
||||
|
||||
## 📖 Examples
|
||||
|
||||
### Different Programming Languages
|
||||
|
||||
```bash
|
||||
# Rust
|
||||
echo "Important note" | kfmtbox --filetype rs
|
||||
|
||||
# Python
|
||||
echo "TODO: Fix this bug" | kfmtbox --filetype py
|
||||
|
||||
# JavaScript
|
||||
echo "This function does magic" | kfmtbox --filetype js
|
||||
|
||||
# SQL
|
||||
echo "Complex query explanation" | kfmtbox --filetype sql
|
||||
```
|
||||
|
||||
### Text Wrapping
|
||||
|
||||
```bash
|
||||
# Long text automatically wraps and balances
|
||||
echo "This is a very long comment that will be automatically wrapped into multiple lines with balanced spacing" | kfmtbox --filetype py --max-width 40
|
||||
```
|
||||
|
||||
### Reformatting Existing Comments
|
||||
|
||||
```bash
|
||||
# Reformat existing flower boxes
|
||||
echo "// ╭─────╮
|
||||
// │Old │
|
||||
// ╰─────╯" | kfmtbox --filename test.rs
|
||||
```
|
||||
|
||||
## 🛠️ Command Line Options
|
||||
|
||||
| Option | Description | Example |
|
||||
|-------------------|---------------------------------------|----------------------|
|
||||
| `-f, --filename` | Detect file type from filename | `--filename main.rs` |
|
||||
| `-t, --filetype` | Specify file type explicitly | `--filetype py` |
|
||||
| `-w, --max-width` | Set maximum line width (default: 120) | `--max-width 80` |
|
||||
| `-h, --help` | Show help information | `--help` |
|
||||
| `-V, --version` | Show version information | `--version` |
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
Create a YAML configuration file to customize comment styles:
|
||||
|
||||
**macOS:** `~/Library/Application Support/kfmtbox/comments.yaml`
|
||||
**Linux:** `~/.config/kfmtbox/comments.yaml`
|
||||
**Windows:** `%APPDATA%\kfmtbox\comments.yaml`
|
||||
|
||||
```yaml
|
||||
comment_styles:
|
||||
# Standard languages
|
||||
rust: "//"
|
||||
python: "#"
|
||||
javascript: "//"
|
||||
typescript: "//"
|
||||
go: "//"
|
||||
java: "//"
|
||||
cpp: "//"
|
||||
c: "//"
|
||||
php: "//"
|
||||
ruby: "#"
|
||||
shell: "#"
|
||||
vim: "\""
|
||||
lua: "--"
|
||||
sql: "--"
|
||||
yaml: "#"
|
||||
toml: "#"
|
||||
ini: ";"
|
||||
dockerfile: "#"
|
||||
makefile: "#"
|
||||
cmake: "#"
|
||||
|
||||
# Custom file types
|
||||
custom: "%%"
|
||||
special: "!!"
|
||||
```
|
||||
|
||||
## 🎯 Supported File Types
|
||||
|
||||
| Language | Extensions | Comment Style |
|
||||
|----------------|---------------------------------|---------------|
|
||||
| **Rust** | `.rs` | `//` |
|
||||
| **Python** | `.py` | `#` |
|
||||
| **JavaScript** | `.js` | `//` |
|
||||
| **TypeScript** | `.ts` | `//` |
|
||||
| **Go** | `.go` | `//` |
|
||||
| **Java** | `.java` | `//` |
|
||||
| **C/C++** | `.c`, `.cpp`, `.h`, `.hpp` | `//` |
|
||||
| **C#** | `.cs` | `//` |
|
||||
| **PHP** | `.php` | `//` |
|
||||
| **Ruby** | `.rb` | `#` |
|
||||
| **Shell** | `.sh`, `.bash`, `.zsh`, `.fish` | `#` |
|
||||
| **Vim** | `.vim` | `"` |
|
||||
| **Lua** | `.lua` | `--` |
|
||||
| **SQL** | `.sql` | `--` |
|
||||
| **YAML** | `.yaml`, `.yml` | `#` |
|
||||
| **TOML** | `.toml` | `#` |
|
||||
| **INI** | `.ini`, `.cfg` | `;` |
|
||||
| **Dockerfile** | `Dockerfile` | `#` |
|
||||
| **Makefile** | `Makefile` | `#` |
|
||||
| **CMake** | `CMakeLists.txt` | `#` |
|
||||
|
||||
## 🔌 Editor Integration
|
||||
|
||||
### Neovim
|
||||
|
||||
Add to your `init.vim` or `init.lua`:
|
||||
|
||||
```vim
|
||||
" Format selected text as flower box
|
||||
vnoremap <leader>fb :!kfmtbox --filename %<CR>
|
||||
|
||||
" Language-specific shortcuts
|
||||
vnoremap <leader>fr :!kfmtbox --filetype rs<CR>
|
||||
vnoremap <leader>fp :!kfmtbox --filetype py<CR>
|
||||
vnoremap <leader>fj :!kfmtbox --filetype js<CR>
|
||||
```
|
||||
|
||||
### VSCode
|
||||
|
||||
Create a custom task in `.vscode/tasks.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Format as Flower Box",
|
||||
"type": "shell",
|
||||
"command": "kfmtbox",
|
||||
"args": ["--filename", "${file}"],
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Emacs
|
||||
|
||||
Add to your `.emacs` or `init.el`:
|
||||
|
||||
```elisp
|
||||
(defun kfmtbox-format-region ()
|
||||
"Format selected region as flower box"
|
||||
(interactive)
|
||||
(shell-command-on-region (region-beginning) (region-end)
|
||||
(format "kfmtbox --filename %s" (buffer-file-name))
|
||||
nil t))
|
||||
|
||||
(global-set-key (kbd "C-c f b") 'kfmtbox-format-region)
|
||||
```
|
||||
|
||||
## 🧪 Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Rust 1.70+ (edition 2021)
|
||||
- Cargo
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/yourusername/kfmtbox.git
|
||||
cd kfmtbox
|
||||
|
||||
# Build in debug mode
|
||||
cargo build
|
||||
|
||||
# Build optimized release
|
||||
cargo build --release
|
||||
|
||||
# Run tests
|
||||
cargo test
|
||||
|
||||
# Check code quality
|
||||
cargo clippy
|
||||
|
||||
# Format code
|
||||
cargo fmt
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
kfmtbox/
|
||||
├── src/
|
||||
│ ├── main.rs # CLI entry point
|
||||
│ ├── lib.rs # Library exports
|
||||
│ ├── cli.rs # Command line argument parsing
|
||||
│ ├── box_renderer.rs # Flower box rendering logic
|
||||
│ ├── text_wrapper.rs # Text wrapping and balancing
|
||||
│ ├── comment_detector.rs # File type and comment style detection
|
||||
│ └── config.rs # YAML configuration handling
|
||||
├── Cargo.toml # Project dependencies and metadata
|
||||
├── README.md # This file
|
||||
├── LICENSE # MIT License
|
||||
└── .github/ # GitHub workflows and templates
|
||||
```
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
||||
|
||||
### Quick Contribution Steps
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Make your changes
|
||||
4. Add tests for new functionality
|
||||
5. Run the test suite (`cargo test`)
|
||||
6. Commit your changes (`git commit -m 'Add amazing feature'`)
|
||||
7. Push to your branch (`git push origin feature/amazing-feature`)
|
||||
8. Open a Pull Request
|
||||
|
||||
## 📋 Roadmap
|
||||
|
||||
- [ ] **Block comment support** for languages like C/C++ (`/* */`)
|
||||
- [ ] **Theming system** with different border styles
|
||||
- [ ] **VSCode extension** for seamless integration
|
||||
- [ ] **JetBrains plugin** for IntelliJ, PyCharm, etc.
|
||||
- [ ] **Auto-detection** of file type from stdin context
|
||||
- [ ] **Configurable padding** and border characters
|
||||
- [ ] **Multi-line input** with automatic paragraph detection
|
||||
|
||||
## 🐛 Bug Reports & Feature Requests
|
||||
|
||||
Found a bug or have an idea? We'd love to hear from you!
|
||||
|
||||
- 🐛 [Report a bug](https://github.com/yourusername/kfmtbox/issues/new?template=bug_report.md)
|
||||
- 💡 [Request a feature](https://github.com/yourusername/kfmtbox/issues/new?template=feature_request.md)
|
||||
- 💬 [Start a discussion](https://github.com/yourusername/kfmtbox/discussions)
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
- Inspired by the need for beautiful, consistent comment formatting
|
||||
- Built with ❤️ using [Rust](https://www.rust-lang.org/)
|
||||
- Uses [clap](https://github.com/clap-rs/clap) for CLI parsing
|
||||
- Configuration powered by [serde_yaml](https://github.com/dtolnay/serde-yaml)
|
||||
|
||||
---
|
||||
|
||||
**Made with ❤️ by the kfmtbox team**
|
||||
|
||||
[⭐ Star this repo](https://github.com/yourusername/kfmtbox) if you find it useful!
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We release patches for security vulnerabilities in the following versions:
|
||||
|
||||
| Version | Supported |
|
||||
|---------|--------------------|
|
||||
| 0.1.x | :white_check_mark: |
|
||||
| < 0.1 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
We take security bugs seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
|
||||
|
||||
### How to Report a Security Vulnerability
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them via email to: [security@example.com](mailto:security@example.com)
|
||||
|
||||
You should receive a response within 48 hours. If for some reason you do not, please follow up via email to ensure we received your original message.
|
||||
|
||||
### What to Include
|
||||
|
||||
Please include the following information in your report:
|
||||
|
||||
- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
- Full paths of source file(s) related to the manifestation of the issue
|
||||
- The location of the affected source code (tag/branch/commit or direct URL)
|
||||
- Any special configuration required to reproduce the issue
|
||||
- Step-by-step instructions to reproduce the issue
|
||||
- Proof-of-concept or exploit code (if possible)
|
||||
- Impact of the issue, including how an attacker might exploit it
|
||||
|
||||
### What to Expect
|
||||
|
||||
After you submit a report, we will:
|
||||
|
||||
1. Confirm receipt of your vulnerability report within 48 hours
|
||||
2. Provide regular updates on our progress
|
||||
3. Credit you in our security advisory (unless you prefer to remain anonymous)
|
||||
|
||||
### Security Best Practices
|
||||
|
||||
When using kfmtbox, please follow these security best practices:
|
||||
|
||||
- **Keep kfmtbox updated** to the latest version
|
||||
- **Validate input** before passing it to kfmtbox
|
||||
- **Use trusted sources** for configuration files
|
||||
- **Review configuration files** before using them
|
||||
- **Run with minimal privileges** when possible
|
||||
|
||||
### Security Considerations
|
||||
|
||||
kfmtbox is designed with security in mind:
|
||||
|
||||
- **No network access** - kfmtbox operates entirely locally
|
||||
- **Input validation** - All input is validated and sanitized
|
||||
- **Memory safety** - Written in Rust for memory safety guarantees
|
||||
- **Dependency auditing** - Regular security audits of dependencies
|
||||
- **Minimal attack surface** - Simple, focused functionality
|
||||
|
||||
### Known Security Issues
|
||||
|
||||
Currently, there are no known security vulnerabilities in kfmtbox.
|
||||
|
||||
### Security Updates
|
||||
|
||||
Security updates will be released as soon as possible after a vulnerability is confirmed and a fix is available. We will:
|
||||
|
||||
- Release a new version with the security fix
|
||||
- Publish a security advisory
|
||||
- Update this document if needed
|
||||
|
||||
### Contact
|
||||
|
||||
For security-related questions or concerns, please contact us at:
|
||||
- Email: [security@example.com](mailto:security@example.com)
|
||||
- GitHub Security Advisories: [Create a private vulnerability report](https://github.com/yourusername/kfmtbox/security/advisories/new)
|
||||
|
||||
Thank you for helping keep kfmtbox and our users safe!
|
||||
@@ -0,0 +1,102 @@
|
||||
# Quick Setup Guide for Package Distribution
|
||||
|
||||
This guide helps you quickly set up `kfmtbox` for distribution across multiple package managers.
|
||||
|
||||
## 🚀 Quick Start (5 minutes)
|
||||
|
||||
### 1. First Release Setup
|
||||
|
||||
```bash
|
||||
# 1. Set up GitHub secrets (in your repository settings)
|
||||
# Go to: Settings > Secrets and variables > Actions
|
||||
# Add these secrets:
|
||||
# - CARGO_REGISTRY_TOKEN (from crates.io account)
|
||||
# - HOMEBREW_CORE_TOKEN (GitHub token with repo access)
|
||||
|
||||
# 2. Create your first release
|
||||
./scripts/release.sh 0.1.0
|
||||
|
||||
# 3. Wait for GitHub Actions to complete
|
||||
# 4. Check the release at: https://github.com/koftwentytwo/kfmtbox/releases
|
||||
```
|
||||
|
||||
### 2. Package Manager Setup
|
||||
|
||||
#### Homebrew (Personal Tap)
|
||||
```bash
|
||||
# Create a new repository: koftwentytwo/homebrew-kfmtbox
|
||||
# Copy Formula/kfmtbox.rb to your tap repository
|
||||
# Users can then install with:
|
||||
brew tap koftwentytwo/kfmtbox
|
||||
brew install kfmtbox
|
||||
```
|
||||
|
||||
#### Cargo (crates.io)
|
||||
```bash
|
||||
# 1. Create account at https://crates.io
|
||||
# 2. Get API token from account settings
|
||||
# 3. Add token to GitHub secrets as CARGO_REGISTRY_TOKEN
|
||||
# 4. GitHub Actions will automatically publish on release
|
||||
```
|
||||
|
||||
#### Arch Linux (AUR)
|
||||
```bash
|
||||
# 1. Create AUR account at https://aur.archlinux.org
|
||||
# 2. Clone the AUR repository:
|
||||
git clone ssh://aur@aur.archlinux.org/kfmtbox.git
|
||||
cd kfmtbox
|
||||
|
||||
# 3. Create PKGBUILD (see PACKAGING.md for template)
|
||||
# 4. Create .SRCINFO: makepkg --printsrcinfo > .SRCINFO
|
||||
# 5. Commit and push
|
||||
```
|
||||
|
||||
## 📋 Pre-Release Checklist
|
||||
|
||||
- [ ] Update `Cargo.toml` version
|
||||
- [ ] Update `CHANGELOG.md`
|
||||
- [ ] Run `cargo test` and `cargo clippy`
|
||||
- [ ] Test installation scripts locally
|
||||
- [ ] Verify all documentation links work
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **GitHub Actions fails**: Check secrets are set correctly
|
||||
2. **Cargo publish fails**: Verify API token and package name
|
||||
3. **Homebrew formula fails**: Check SHA256 hash in formula
|
||||
4. **Installation scripts fail**: Test on clean system
|
||||
|
||||
### Getting Help
|
||||
|
||||
- Check the full [PACKAGING.md](PACKAGING.md) for detailed instructions
|
||||
- Review [GitHub Actions logs](https://github.com/koftwentytwo/kfmtbox/actions)
|
||||
- Test installation scripts on different platforms
|
||||
|
||||
## 🎯 Success Metrics
|
||||
|
||||
Track your distribution success:
|
||||
|
||||
- **Downloads**: GitHub release statistics
|
||||
- **Cargo installs**: `cargo install --list | grep kfmtbox`
|
||||
- **Homebrew installs**: `brew info kfmtbox`
|
||||
- **User feedback**: GitHub issues and discussions
|
||||
|
||||
## 📈 Next Steps
|
||||
|
||||
After successful initial release:
|
||||
|
||||
1. **Monitor usage**: Check download statistics
|
||||
2. **Gather feedback**: Respond to issues and feature requests
|
||||
3. **Expand distribution**: Add more package managers
|
||||
4. **Improve documentation**: Update README with user examples
|
||||
5. **Community building**: Share on social media and forums
|
||||
|
||||
## 🚀 Pro Tips
|
||||
|
||||
- **Start small**: Begin with GitHub releases and Cargo
|
||||
- **Automate everything**: Use GitHub Actions for all releases
|
||||
- **Test thoroughly**: Verify installation on multiple platforms
|
||||
- **Document everything**: Keep PACKAGING.md updated
|
||||
- **Engage community**: Respond to issues and feature requests quickly
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
# Style Guide for kfmtbox
|
||||
|
||||
This project follows strict coding standards based on C++ Allman brace style and formatting preferences.
|
||||
|
||||
## IDE Integration Strategy
|
||||
|
||||
With RustIDE using nightly Rust, we now have **full Allman brace style support**:
|
||||
|
||||
1. **IDE Formatting**: Uses Allman brace style (opening braces on new lines)
|
||||
2. **Automatic Enforcement**: Allman style applied automatically by rustfmt
|
||||
3. **Consistent Indentation**: 3-space indentation (matches your C++ style)
|
||||
4. **Quality Checks**: Clippy enforces code quality and style consistency
|
||||
|
||||
## Brace Style: Allman Style (Manual Enforcement)
|
||||
|
||||
**Opening braces `{` should be on a new line after control structures when manually formatting.**
|
||||
|
||||
### ✅ Correct (Allman Style):
|
||||
```rust
|
||||
if condition
|
||||
{
|
||||
// code here
|
||||
}
|
||||
|
||||
for item in items
|
||||
{
|
||||
// code here
|
||||
}
|
||||
|
||||
while condition
|
||||
{
|
||||
// code here
|
||||
}
|
||||
|
||||
match value
|
||||
{
|
||||
Some(x) => {
|
||||
// code here
|
||||
}
|
||||
None => {
|
||||
// code here
|
||||
}
|
||||
}
|
||||
|
||||
impl MyStruct
|
||||
{
|
||||
fn method(&self)
|
||||
{
|
||||
// code here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ Incorrect (K&R Style):
|
||||
```rust
|
||||
if condition {
|
||||
// code here
|
||||
}
|
||||
|
||||
for item in items {
|
||||
// code here
|
||||
}
|
||||
|
||||
impl MyStruct {
|
||||
fn method(&self) {
|
||||
// code here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Formatting Configuration
|
||||
|
||||
### For IDE Integration (Recommended)
|
||||
- **Indentation**: 3 spaces (matches your C++ style)
|
||||
- **Line length**: 100 characters
|
||||
- **Brace style**: Allman style (opening braces on new lines)
|
||||
- **Automatic enforcement**: Applied by nightly rustfmt
|
||||
|
||||
### For Manual Allman Style (Optional)
|
||||
If you want to manually format with Allman brace style:
|
||||
|
||||
```bash
|
||||
# Use the nightly formatting script
|
||||
./scripts/format.sh
|
||||
|
||||
# Or manually use nightly rustfmt
|
||||
rustup run nightly cargo fmt --config rustfmt-nightly.toml
|
||||
```
|
||||
|
||||
### IDE Setup
|
||||
Your RustIDE with nightly Rust will automatically:
|
||||
- Use 3-space indentation
|
||||
- Enforce 100-character line limits
|
||||
- Format with Allman brace style (opening braces on new lines)
|
||||
- Run clippy for quality checks
|
||||
- Apply consistent import grouping
|
||||
|
||||
## Enforcement
|
||||
|
||||
### IDE Integration (Primary)
|
||||
Your IDE will automatically:
|
||||
1. **Format code** with 3-space indentation and 100-char lines
|
||||
2. **Run clippy** for quality and style warnings
|
||||
3. **Check formatting** on save
|
||||
4. **Provide suggestions** for improvements
|
||||
|
||||
### Manual Enforcement (Secondary)
|
||||
For Allman brace style specifically:
|
||||
1. **Code review** - All PRs should follow Allman style where possible
|
||||
2. **Documentation** - This style guide serves as reference
|
||||
3. **Optional script** - Use `./scripts/format.sh` for Allman formatting
|
||||
|
||||
### Automated Checks
|
||||
```bash
|
||||
# Check formatting (IDE compatible)
|
||||
cargo fmt --check
|
||||
|
||||
# Run clippy for quality warnings
|
||||
cargo clippy --all-targets --all-features
|
||||
|
||||
# Run tests
|
||||
cargo test
|
||||
|
||||
# Optional: Format with Allman style
|
||||
./scripts/format.sh
|
||||
```
|
||||
|
||||
## Configuration Files
|
||||
|
||||
- `rustfmt.toml` - Stable Rust formatting (3-space indentation, 100-char lines)
|
||||
- `rustfmt-nightly.toml` - Nightly Rust formatting (includes Allman brace style)
|
||||
- `clippy.toml` - Linting rules for code quality
|
||||
- `Cargo.toml` - Project-level linting configuration
|
||||
|
||||
## Examples
|
||||
|
||||
### Function Definitions
|
||||
```rust
|
||||
fn my_function(param1: String, param2: usize) -> Result<String, Error>
|
||||
{
|
||||
if param1.is_empty()
|
||||
{
|
||||
return Err(Error::InvalidInput);
|
||||
}
|
||||
|
||||
for i in 0..param2
|
||||
{
|
||||
// process each item
|
||||
}
|
||||
|
||||
Ok("success".to_string())
|
||||
}
|
||||
```
|
||||
|
||||
### Struct and Impl Blocks
|
||||
```rust
|
||||
pub struct MyStruct
|
||||
{
|
||||
field1: String,
|
||||
field2: usize,
|
||||
}
|
||||
|
||||
impl MyStruct
|
||||
{
|
||||
pub fn new(field1: String, field2: usize) -> Self
|
||||
{
|
||||
Self { field1, field2 }
|
||||
}
|
||||
|
||||
pub fn process(&self) -> Result<(), Error>
|
||||
{
|
||||
if self.field1.is_empty()
|
||||
{
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Match Statements
|
||||
```rust
|
||||
match result
|
||||
{
|
||||
Ok(value) => {
|
||||
println!("Success: {}", value);
|
||||
}
|
||||
Err(error) => {
|
||||
eprintln!("Error: {}", error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Integration with CI/CD
|
||||
|
||||
The GitHub Actions workflow will:
|
||||
1. Check formatting with `cargo fmt --check`
|
||||
2. Run clippy with strict rules
|
||||
3. Run tests
|
||||
4. Build for multiple platforms
|
||||
|
||||
All code must pass these checks before merging.
|
||||
|
||||
## Migration Guide
|
||||
|
||||
If you have existing code that doesn't follow Allman style:
|
||||
|
||||
1. **Manual conversion**: Update braces to be on new lines
|
||||
2. **Use nightly formatter**: `rustup run nightly cargo fmt --config rustfmt-nightly.toml`
|
||||
3. **Verify with clippy**: `cargo clippy --all-targets --all-features`
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Consistency**: Matches your C++ coding style
|
||||
- **Readability**: Clear visual separation of control structures
|
||||
- **Maintainability**: Easier to read and modify code
|
||||
- **Professional**: Industry-standard formatting for many C++ projects
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Clippy configuration file
|
||||
# This file should be in the project root
|
||||
|
||||
# Allow explicit return statements
|
||||
# Note: needless-return is not a valid clippy.toml option
|
||||
# Instead, we use the Cargo.toml configuration
|
||||
|
||||
# Other valid clippy.toml options:
|
||||
cognitive-complexity-threshold = 10
|
||||
too-many-arguments-threshold = 7
|
||||
too-many-lines-threshold = 100
|
||||
type-complexity-threshold = 200
|
||||
large-error-threshold = 128
|
||||
# Bytes (clippy default 512000). 256 cannot be met by ordinary frames: measured debug-build frames are 297-1633 bytes
|
||||
# (largest: render_flower_box at 1633, extract_content_from_box at 1551). 2048 keeps a gate just above them.
|
||||
stack-size-threshold = 2048
|
||||
enum-variant-size-threshold = 200
|
||||
array-size-threshold = 512
|
||||
max-fn-params-bools = 3
|
||||
max-struct-bools = 3
|
||||
max-trait-bounds = 3
|
||||
literal-representation-threshold = 10
|
||||
min-ident-chars-threshold = 3
|
||||
single-char-binding-names-threshold = 2
|
||||
missing-docs-in-crate-items = true
|
||||
check-private-items = true
|
||||
arithmetic-side-effects-allowed = []
|
||||
allow-unwrap-in-tests = false
|
||||
allow-expect-in-tests = false
|
||||
allow-panic-in-tests = false
|
||||
allow-dbg-in-tests = false
|
||||
allow-print-in-tests = false
|
||||
semicolon-inside-block-ignore-singleline = false
|
||||
semicolon-outside-block-ignore-multiline = false
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
# kfmtbox installation script for Windows PowerShell
|
||||
# Run with: powershell -ExecutionPolicy Bypass -File install.ps1
|
||||
|
||||
param(
|
||||
[string]$Version = "latest"
|
||||
)
|
||||
|
||||
# Configuration
|
||||
$Repo = "koftwentytwo/kfmtbox"
|
||||
$BinaryName = "kfmtbox.exe"
|
||||
$InstallDir = "$env:USERPROFILE\AppData\Local\kfmtbox\bin"
|
||||
|
||||
# Colors for output
|
||||
function Write-ColorOutput($ForegroundColor) {
|
||||
$fc = $host.UI.RawUI.ForegroundColor
|
||||
$host.UI.RawUI.ForegroundColor = $ForegroundColor
|
||||
if ($args) {
|
||||
Write-Output $args
|
||||
} else {
|
||||
$input | Write-Output
|
||||
}
|
||||
$host.UI.RawUI.ForegroundColor = $fc
|
||||
}
|
||||
|
||||
# Detect architecture
|
||||
function Get-Architecture {
|
||||
if ([Environment]::Is64BitOperatingSystem) {
|
||||
return "x86_64"
|
||||
} else {
|
||||
return "x86"
|
||||
}
|
||||
}
|
||||
|
||||
# Get latest release version
|
||||
function Get-LatestVersion {
|
||||
try {
|
||||
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest"
|
||||
return $response.tag_name
|
||||
} catch {
|
||||
Write-ColorOutput Red "Failed to get latest version: $_"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Download and install binary
|
||||
function Install-Binary {
|
||||
param(
|
||||
[string]$Version,
|
||||
[string]$Architecture
|
||||
)
|
||||
|
||||
$assetName = "kfmtbox-windows-$Architecture.exe"
|
||||
$downloadUrl = "https://github.com/$Repo/releases/download/$Version/$assetName"
|
||||
$tempFile = "$env:TEMP\$assetName"
|
||||
|
||||
Write-ColorOutput Blue "Downloading $assetName..."
|
||||
try {
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tempFile
|
||||
} catch {
|
||||
Write-ColorOutput Red "Failed to download binary: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Create install directory
|
||||
if (!(Test-Path $InstallDir)) {
|
||||
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
||||
}
|
||||
|
||||
# Move binary to install directory
|
||||
Move-Item -Path $tempFile -Destination "$InstallDir\$BinaryName" -Force
|
||||
|
||||
Write-ColorOutput Green "Installed $BinaryName to $InstallDir\$BinaryName"
|
||||
}
|
||||
|
||||
# Add to PATH
|
||||
function Add-ToPath {
|
||||
$currentPath = [Environment]::GetEnvironmentVariable("PATH", "User")
|
||||
|
||||
if ($currentPath -notlike "*$InstallDir*") {
|
||||
Write-ColorOutput Yellow "Adding $InstallDir to PATH..."
|
||||
$newPath = "$currentPath;$InstallDir"
|
||||
[Environment]::SetEnvironmentVariable("PATH", $newPath, "User")
|
||||
Write-ColorOutput Green "Added to PATH. Please restart your terminal."
|
||||
} else {
|
||||
Write-ColorOutput Green "Already in PATH"
|
||||
}
|
||||
}
|
||||
|
||||
# Main installation function
|
||||
function Main {
|
||||
Write-ColorOutput Blue "Installing kfmtbox..."
|
||||
|
||||
# Detect architecture
|
||||
$arch = Get-Architecture
|
||||
Write-ColorOutput Blue "Detected architecture: $arch"
|
||||
|
||||
# Get version
|
||||
if ($Version -eq "latest") {
|
||||
$version = Get-LatestVersion
|
||||
} else {
|
||||
$version = $Version
|
||||
}
|
||||
Write-ColorOutput Blue "Version: $version"
|
||||
|
||||
# Install binary
|
||||
Install-Binary -Version $version -Architecture $arch
|
||||
|
||||
# Add to PATH
|
||||
Add-ToPath
|
||||
|
||||
Write-ColorOutput Green "Installation complete!"
|
||||
Write-ColorOutput Blue "Try running: kfmtbox --help"
|
||||
}
|
||||
|
||||
# Check if running as administrator
|
||||
if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
|
||||
Write-ColorOutput Red "This script should not be run as administrator"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check dependencies
|
||||
try {
|
||||
Invoke-WebRequest -Uri "https://github.com" -UseBasicParsing | Out-Null
|
||||
} catch {
|
||||
Write-ColorOutput Red "Internet connection required for installation"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Run main function
|
||||
Main
|
||||
Executable
+143
@@ -0,0 +1,143 @@
|
||||
#!/bin/bash
|
||||
|
||||
# kfmtbox installation script
|
||||
# Supports Linux, macOS, and Windows (via WSL)
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
REPO="koftwentytwo/kfmtbox"
|
||||
BINARY_NAME="kfmtbox"
|
||||
INSTALL_DIR="${HOME}/.local/bin"
|
||||
|
||||
# Detect OS and architecture
|
||||
detect_platform() {
|
||||
local os arch
|
||||
|
||||
case "$(uname -s)" in
|
||||
Linux*) os="linux" ;;
|
||||
Darwin*) os="macos" ;;
|
||||
CYGWIN*|MINGW*|MSYS*) os="windows" ;;
|
||||
*) echo -e "${RED}Unsupported operating system${NC}"; exit 1 ;;
|
||||
esac
|
||||
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64) arch="x86_64" ;;
|
||||
arm64|aarch64) arch="aarch64" ;;
|
||||
*) echo -e "${RED}Unsupported architecture${NC}"; exit 1 ;;
|
||||
esac
|
||||
|
||||
echo "${os}-${arch}"
|
||||
}
|
||||
|
||||
# Get latest release version
|
||||
get_latest_version() {
|
||||
curl -s "https://api.github.com/repos/${REPO}/releases/latest" | \
|
||||
grep '"tag_name":' | \
|
||||
sed -E 's/.*"([^"]+)".*/\1/'
|
||||
}
|
||||
|
||||
# Download and install binary
|
||||
install_binary() {
|
||||
local platform=$1
|
||||
local version=$2
|
||||
local asset_name
|
||||
|
||||
# Determine asset name based on platform
|
||||
case "$platform" in
|
||||
"linux-x86_64")
|
||||
asset_name="kfmtbox-linux-x86_64"
|
||||
;;
|
||||
"macos-x86_64")
|
||||
asset_name="kfmtbox-macos-x86_64"
|
||||
;;
|
||||
"macos-aarch64")
|
||||
asset_name="kfmtbox-macos-aarch64"
|
||||
;;
|
||||
"windows-x86_64")
|
||||
asset_name="kfmtbox-windows-x86_64.exe"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unsupported platform: ${platform}${NC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local download_url="https://github.com/${REPO}/releases/download/${version}/${asset_name}"
|
||||
local temp_file="/tmp/${asset_name}"
|
||||
|
||||
echo -e "${BLUE}Downloading ${asset_name}...${NC}"
|
||||
curl -L -o "$temp_file" "$download_url"
|
||||
|
||||
# Create install directory if it doesn't exist
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
|
||||
# Make binary executable and move to install directory
|
||||
chmod +x "$temp_file"
|
||||
mv "$temp_file" "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
|
||||
echo -e "${GREEN}Installed ${BINARY_NAME} to ${INSTALL_DIR}/${BINARY_NAME}${NC}"
|
||||
}
|
||||
|
||||
# Add to PATH if needed
|
||||
add_to_path() {
|
||||
local shell_rc
|
||||
|
||||
case "$SHELL" in
|
||||
*/zsh) shell_rc="${HOME}/.zshrc" ;;
|
||||
*/bash) shell_rc="${HOME}/.bashrc" ;;
|
||||
*) shell_rc="${HOME}/.profile" ;;
|
||||
esac
|
||||
|
||||
if ! echo "$PATH" | grep -q "${INSTALL_DIR}"; then
|
||||
echo -e "${YELLOW}Adding ${INSTALL_DIR} to PATH in ${shell_rc}${NC}"
|
||||
echo "export PATH=\"${INSTALL_DIR}:\$PATH\"" >> "$shell_rc"
|
||||
echo -e "${GREEN}Please restart your shell or run: source ${shell_rc}${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main installation function
|
||||
main() {
|
||||
echo -e "${BLUE}Installing kfmtbox...${NC}"
|
||||
|
||||
# Detect platform
|
||||
local platform
|
||||
platform=$(detect_platform)
|
||||
echo -e "${BLUE}Detected platform: ${platform}${NC}"
|
||||
|
||||
# Get latest version
|
||||
local version
|
||||
version=$(get_latest_version)
|
||||
echo -e "${BLUE}Latest version: ${version}${NC}"
|
||||
|
||||
# Install binary
|
||||
install_binary "$platform" "$version"
|
||||
|
||||
# Add to PATH
|
||||
add_to_path
|
||||
|
||||
echo -e "${GREEN}Installation complete!${NC}"
|
||||
echo -e "${BLUE}Try running: kfmtbox --help${NC}"
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
echo -e "${RED}This script should not be run as root${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check dependencies
|
||||
if ! command -v curl &> /dev/null; then
|
||||
echo -e "${RED}curl is required but not installed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
@@ -0,0 +1,66 @@
|
||||
Project Name: kfmtbox
|
||||
Purpose: A Rust-based command-line utility that wraps one or more lines of text in a “flower box” style comment, using the appropriate comment style for the file type.
|
||||
|
||||
⸻
|
||||
|
||||
Overview:
|
||||
|
||||
Create a CLI tool (kfmtbox) that:
|
||||
• Detects the file type from extension or CLI argument
|
||||
• Applies a “flower box” style comment block using the correct line comment syntax
|
||||
• Reads from stdin, outputs to stdout
|
||||
• Replaces existing flower box comments if already present
|
||||
• Ensures consistent formatting in monospace terminal environments
|
||||
• Is designed for use from text editors like neovim via hotkeys
|
||||
|
||||
⸻
|
||||
|
||||
Core Features:
|
||||
1. Input/Output:
|
||||
• Accepts input from stdin
|
||||
• Sends formatted result to stdout
|
||||
2. Comment Style Detection:
|
||||
• Uses --filename or --filetype CLI flag
|
||||
• Matches file extension to a known set of comment styles
|
||||
• Falls back to a default style (#) if unknown
|
||||
3. Comment Style Mapping:
|
||||
• Hardcoded map of common file extensions and their line comment styles
|
||||
• Supports user-defined YAML config at ~/.config/kfmtbox/comments.yaml
|
||||
4. Line Formatting Rules:
|
||||
• Max line length of 120 characters
|
||||
• If the input line(s) exceed a certain length, wrap and rebalance them
|
||||
• Wrapped lines must be as evenly sized as possible
|
||||
• Flower box must always be a perfect rectangle
|
||||
• Center content with padding between borders
|
||||
5. Multiline Input:
|
||||
• Treat multiple selected lines as one input block
|
||||
• Format as a single, contiguous box
|
||||
6. Existing Comment Detection:
|
||||
• Detect if the input is already in a flower box
|
||||
• If so, extract content and reformat with updated layout
|
||||
7. Configuration:
|
||||
• Comment styles can be defined in a YAML config file
|
||||
• Config file contains mappings of filetypes to line comment prefixes
|
||||
8. CLI Parameters:
|
||||
• --filename or --filetype to specify source file context
|
||||
• May include future flags for --max-width, --theme, etc.
|
||||
9. Editor Integration:
|
||||
• Designed for invocation via mapped hotkey in Neovim
|
||||
• Minimal output dependencies (pure stdout)
|
||||
10. Development Notes:
|
||||
• Written in idiomatic Rust
|
||||
• Separated modules for CLI parsing, box rendering, and wrapping
|
||||
• CLI powered by clap
|
||||
• Optional YAML parsing via serde_yaml
|
||||
11. Testing and Usability:
|
||||
• Unit tests for core logic
|
||||
• Can be built as a binary and tested via piping from command line
|
||||
|
||||
⸻
|
||||
|
||||
Future Enhancements (Optional):
|
||||
• Block comment support
|
||||
• Theming and customizable border styles
|
||||
• VSCode/JetBrains plugin integrations
|
||||
• Auto-detection of filetype via stdin context
|
||||
• Support for configurable max width or padding
|
||||
@@ -0,0 +1,10 @@
|
||||
# RustRover project configuration
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
components = ["rustfmt", "clippy"]
|
||||
|
||||
[clippy]
|
||||
all-targets = true
|
||||
all-features = true
|
||||
warnings = ["clippy::all"]
|
||||
allow = ["clippy::needless_return", "clippy::redundant_else"]
|
||||
@@ -0,0 +1,58 @@
|
||||
# Rustfmt configuration file for nightly Rust
|
||||
# Based on your .clang-format preferences with Allman brace style
|
||||
# This file should be used with nightly Rust toolchain
|
||||
|
||||
# Indentation - matches your IndentWidth: 3, TabWidth: 3, UseTab: Never
|
||||
tab_spaces = 3
|
||||
|
||||
# Line length - matches your ColumnLimit: 100
|
||||
max_width = 100
|
||||
|
||||
# Edition
|
||||
edition = "2021"
|
||||
|
||||
# Brace style - matches your BreakBeforeBraces: Allman
|
||||
brace_style = "AlwaysNextLine" # Opening braces on new lines
|
||||
control_brace_style = "AlwaysNextLine" # Control structures with braces on new lines
|
||||
|
||||
# Comments - matches your AlignTrailingComments: true
|
||||
wrap_comments = true
|
||||
comment_width = 100
|
||||
normalize_comments = false # ReflowComments: false
|
||||
|
||||
# Imports and modules
|
||||
imports_granularity = "Crate"
|
||||
imports_layout = "Mixed"
|
||||
group_imports = "StdExternalCrate"
|
||||
|
||||
# Functions and expressions
|
||||
fn_single_line = false # AllowShortFunctionsOnASingleLine: None
|
||||
where_single_line = false
|
||||
|
||||
# Structs and enums
|
||||
struct_field_align_threshold = 0
|
||||
enum_discrim_align_threshold = 0
|
||||
|
||||
# Spacing
|
||||
space_before_colon = false
|
||||
space_after_colon = true
|
||||
spaces_around_ranges = false
|
||||
|
||||
# Trailing commas
|
||||
trailing_comma = "Vertical"
|
||||
|
||||
# Empty lines
|
||||
empty_item_single_line = true
|
||||
max_empty_lines_to_keep = 3 # MaxEmptyLinesToKeep: 3
|
||||
|
||||
# String formatting
|
||||
format_strings = true
|
||||
format_code_in_doc_comments = true
|
||||
|
||||
# Misc
|
||||
remove_nested_parens = true
|
||||
use_try_shorthand = true
|
||||
use_field_init_shorthand = true
|
||||
force_explicit_abi = true
|
||||
|
||||
# This configuration enforces your C++ Allman brace style in Rust
|
||||
@@ -0,0 +1,13 @@
|
||||
# KofTwentyTwo rustfmt configuration (K22-CODE-RS). Stable-channel options only, so
|
||||
# `cargo fmt --check` behaves the same on every toolchain.
|
||||
edition = "2021"
|
||||
# Kingsrook: 3-space indentation (tab_spaces is a stable option).
|
||||
tab_spaces = 3
|
||||
hard_tabs = false
|
||||
newline_style = "Unix"
|
||||
# Kingsrook: no practical line limit. 200 keeps rustfmt's wrapping heuristics sane.
|
||||
max_width = 200
|
||||
use_field_init_shorthand = true
|
||||
use_try_shorthand = true
|
||||
# Not set: brace_style = "AlwaysNextLine" and blank_lines_upper_bound are nightly-only.
|
||||
# Rust therefore keeps rustfmt's same-line braces (profile rule K22-CODE-RS-02).
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Format script for kfmtbox with Allman brace style
|
||||
# This script uses nightly Rust to format code with Allman brace style
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔧 Formatting code with Allman brace style..."
|
||||
|
||||
# Check if nightly Rust is installed
|
||||
if ! /Users/james.maes/.cargo/bin/rustup show | grep -q "nightly"; then
|
||||
echo "📦 Installing nightly Rust..."
|
||||
/Users/james.maes/.cargo/bin/rustup install nightly
|
||||
fi
|
||||
|
||||
# Use nightly rustfmt with Allman brace style configuration
|
||||
echo "🎨 Running rustfmt with Allman brace style..."
|
||||
/Users/james.maes/.cargo/bin/rustup run nightly cargo fmt
|
||||
|
||||
echo "✅ Formatting complete!"
|
||||
echo ""
|
||||
echo "📋 Style applied:"
|
||||
echo " - 3-space indentation"
|
||||
echo " - 100-character line limit"
|
||||
echo " - Allman brace style (opening braces on new lines)"
|
||||
echo " - Consistent spacing and formatting"
|
||||
echo ""
|
||||
echo "💡 Your RustIDE should now format with Allman brace style automatically!"
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
|
||||
# kfmtbox release script
|
||||
# Usage: ./scripts/release.sh <version>
|
||||
# Example: ./scripts/release.sh 0.1.0
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Check if version is provided
|
||||
if [ $# -eq 0 ]; then
|
||||
echo -e "${RED}Error: Version number required${NC}"
|
||||
echo "Usage: $0 <version>"
|
||||
echo "Example: $0 0.1.0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION=$1
|
||||
TAG="v${VERSION}"
|
||||
|
||||
echo -e "${BLUE}Releasing kfmtbox version ${VERSION}${NC}"
|
||||
|
||||
# Check if we're in a git repository
|
||||
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
echo -e "${RED}Error: Not in a git repository${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if working directory is clean
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
echo -e "${RED}Error: Working directory is not clean${NC}"
|
||||
echo "Please commit or stash your changes before releasing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if tag already exists
|
||||
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
echo -e "${RED}Error: Tag $TAG already exists${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Update version in Cargo.toml
|
||||
echo -e "${YELLOW}Updating version in Cargo.toml...${NC}"
|
||||
sed -i.bak "s/^version = \".*\"/version = \"${VERSION}\"/" Cargo.toml
|
||||
rm Cargo.toml.bak
|
||||
|
||||
# Update version in Homebrew formula
|
||||
echo -e "${YELLOW}Updating version in Homebrew formula...${NC}"
|
||||
sed -i.bak "s/url \"https:\/\/github\.com\/koftwentytwo\/kfmtbox\/archive\/v.*\.tar\.gz\"/url \"https:\/\/github\.com\/koftwentytwo\/kfmtbox\/archive\/v${VERSION}\.tar\.gz\"/" Formula/kfmtbox.rb
|
||||
rm Formula/kfmtbox.rb.bak
|
||||
|
||||
# Update CHANGELOG.md (if it exists)
|
||||
if [ -f "CHANGELOG.md" ]; then
|
||||
echo -e "${YELLOW}Please update CHANGELOG.md with the new version${NC}"
|
||||
echo "Press Enter when done..."
|
||||
read -r
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
echo -e "${YELLOW}Running tests...${NC}"
|
||||
cargo test
|
||||
|
||||
# Run clippy
|
||||
echo -e "${YELLOW}Running clippy...${NC}"
|
||||
cargo clippy --all-targets --all-features
|
||||
|
||||
# Check formatting
|
||||
echo -e "${YELLOW}Checking formatting...${NC}"
|
||||
cargo fmt --check
|
||||
|
||||
# Build release
|
||||
echo -e "${YELLOW}Building release...${NC}"
|
||||
cargo build --release
|
||||
|
||||
# Commit changes
|
||||
echo -e "${YELLOW}Committing changes...${NC}"
|
||||
git add Cargo.toml Formula/kfmtbox.rb CHANGELOG.md
|
||||
git commit -m "Release version ${VERSION}"
|
||||
|
||||
# Create and push tag
|
||||
echo -e "${YELLOW}Creating and pushing tag...${NC}"
|
||||
git tag -a "$TAG" -m "Release version ${VERSION}"
|
||||
git push origin main
|
||||
git push origin "$TAG"
|
||||
|
||||
echo -e "${GREEN}Release ${VERSION} created successfully!${NC}"
|
||||
echo -e "${BLUE}Next steps:${NC}"
|
||||
echo "1. Wait for GitHub Actions to build and create the release"
|
||||
echo "2. Update package managers (Homebrew, AUR, etc.)"
|
||||
echo "3. Announce the release on social media/forums"
|
||||
|
||||
# Optional: Open GitHub releases page
|
||||
if command -v open >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Opening GitHub releases page...${NC}"
|
||||
open "https://github.com/koftwentytwo/kfmtbox/releases"
|
||||
elif command -v xdg-open >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Opening GitHub releases page...${NC}"
|
||||
xdg-open "https://github.com/koftwentytwo/kfmtbox/releases"
|
||||
fi
|
||||
@@ -0,0 +1,128 @@
|
||||
use crate::{comment_detector::CommentStyle, text_wrapper::TextWrapper};
|
||||
|
||||
pub struct BoxRenderer {
|
||||
comment_style: CommentStyle,
|
||||
text_wrapper: TextWrapper,
|
||||
}
|
||||
|
||||
impl BoxRenderer {
|
||||
#[must_use]
|
||||
pub const fn new(comment_style: CommentStyle, max_width: usize) -> Self {
|
||||
#[allow(clippy::needless_return)]
|
||||
return Self {
|
||||
comment_style,
|
||||
text_wrapper: TextWrapper::new(max_width),
|
||||
};
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn render_flower_box(&self, content: &str) -> String {
|
||||
// Check if content is already in a flower box
|
||||
let clean_content = self.extract_content_from_box(content);
|
||||
|
||||
// Wrap and balance the text
|
||||
let wrapped_lines = self.text_wrapper.wrap_text(&clean_content);
|
||||
let balanced_lines = self.text_wrapper.balance_lines(wrapped_lines);
|
||||
|
||||
// Find the widest line, in characters, for the box width
|
||||
let max_line_len = balanced_lines.iter().map(|line| return line.chars().count()).max().unwrap_or(0);
|
||||
|
||||
// Inner width: one space either side of the text, minimum of 10
|
||||
let inner_width = max_line_len.saturating_add(2).max(10);
|
||||
let prefix = &self.comment_style.prefix;
|
||||
let border = "─".repeat(inner_width);
|
||||
|
||||
// Build the flower box
|
||||
let mut result = Vec::new();
|
||||
|
||||
// Top border
|
||||
result.push(format!("{prefix} ╭{border}╮"));
|
||||
|
||||
// Content lines
|
||||
for line in balanced_lines {
|
||||
let padding = inner_width.saturating_sub(line.chars().count()).saturating_sub(2);
|
||||
result.push(format!("{prefix} │ {line}{} │", " ".repeat(padding)));
|
||||
}
|
||||
|
||||
// Bottom border
|
||||
result.push(format!("{prefix} ╰{border}╯"));
|
||||
|
||||
return result.join("\n");
|
||||
}
|
||||
|
||||
/// Extracts content from an existing flower box comment, or returns the input unchanged.
|
||||
fn extract_content_from_box(&self, content: &str) -> String {
|
||||
let lines: Vec<&str> = content.lines().collect();
|
||||
let (Some(first), Some(last)) = (lines.first(), lines.last()) else {
|
||||
return content.to_string();
|
||||
};
|
||||
if lines.len() < 3 {
|
||||
return content.to_string();
|
||||
}
|
||||
|
||||
// Check if this looks like a flower box
|
||||
let (first_line, last_line) = (first.trim(), last.trim());
|
||||
if !(first_line.contains('╭') && first_line.contains('╮') && last_line.contains('╰') && last_line.contains('╯')) {
|
||||
return content.to_string();
|
||||
}
|
||||
|
||||
let prefix = self.comment_style.prefix.as_str();
|
||||
let mut content_lines = Vec::new();
|
||||
|
||||
// Extract content from the middle lines
|
||||
for line in lines.iter().skip(1).take(lines.len().saturating_sub(2)) {
|
||||
// Remove the comment prefix first
|
||||
let clean_line = if line.trim_start().starts_with(prefix) {
|
||||
line.split_once(prefix).map_or(*line, |(_, rest)| return rest)
|
||||
} else {
|
||||
line
|
||||
};
|
||||
|
||||
// The content sits between the first two pipe characters
|
||||
let mut parts = clean_line.split('│').skip(1);
|
||||
if let (Some(inner), Some(_)) = (parts.next(), parts.next()) {
|
||||
if !inner.is_empty() {
|
||||
content_lines.push(inner.trim().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
return content_lines.join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::comment_detector::CommentStyle;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if an assertion fails.
|
||||
#[test]
|
||||
fn test_render_flower_box() {
|
||||
let comment_style = CommentStyle::new("//".to_string());
|
||||
let renderer = BoxRenderer::new(comment_style, 80);
|
||||
let content = "Hello, world!";
|
||||
let result = renderer.render_flower_box(content);
|
||||
|
||||
assert!(result.contains("╭"));
|
||||
assert!(result.contains("╮"));
|
||||
assert!(result.contains("╰"));
|
||||
assert!(result.contains("╯"));
|
||||
assert!(result.contains("Hello, world!"));
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if an assertion fails.
|
||||
#[test]
|
||||
fn test_extract_content_from_box() {
|
||||
let comment_style = CommentStyle::new("//".to_string());
|
||||
let renderer = BoxRenderer::new(comment_style, 80);
|
||||
|
||||
let boxed_content = "// ╭─────────────╮\n// │ Hello, world! │\n// ╰─────────────╯";
|
||||
let extracted = renderer.extract_content_from_box(boxed_content);
|
||||
|
||||
assert_eq!(extracted, "Hello, world!");
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "kfmtbox")]
|
||||
#[command(about = "A command-line utility that wraps text in flower box style comments")]
|
||||
#[command(version)]
|
||||
pub struct Cli {
|
||||
/// Input filename for file type detection
|
||||
#[arg(short = 'f', long = "filename")]
|
||||
pub filename: Option<String>,
|
||||
|
||||
/// File type for comment style detection
|
||||
#[arg(short = 't', long = "filetype")]
|
||||
pub filetype: Option<String>,
|
||||
|
||||
/// Maximum line width (default: 120)
|
||||
#[arg(short = 'w', long = "max-width", default_value = "120")]
|
||||
pub max_width: usize,
|
||||
|
||||
/// Verbose mode to show operations and decisions
|
||||
#[arg(short = 'v', long = "verbose")]
|
||||
pub verbose: bool,
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::config::Config;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CommentStyle {
|
||||
pub prefix: String,
|
||||
pub is_block: bool,
|
||||
}
|
||||
|
||||
impl CommentStyle {
|
||||
#[must_use]
|
||||
pub const fn new(prefix: String) -> Self {
|
||||
return Self { prefix, is_block: false };
|
||||
}
|
||||
}
|
||||
|
||||
/// Default comment prefixes for common file types.
|
||||
const DEFAULT_STYLES: &[(&str, &str)] = &[
|
||||
("rs", "//"),
|
||||
("py", "#"),
|
||||
("js", "//"),
|
||||
("ts", "//"),
|
||||
("go", "//"),
|
||||
("java", "//"),
|
||||
("cpp", "//"),
|
||||
("c", "//"),
|
||||
("h", "//"),
|
||||
("hpp", "//"),
|
||||
("cs", "//"),
|
||||
("php", "//"),
|
||||
("rb", "#"),
|
||||
("sh", "#"),
|
||||
("bash", "#"),
|
||||
("zsh", "#"),
|
||||
("fish", "#"),
|
||||
("vim", "\""),
|
||||
("lua", "--"),
|
||||
("sql", "--"),
|
||||
("yaml", "#"),
|
||||
("yml", "#"),
|
||||
("toml", "#"),
|
||||
("ini", ";"),
|
||||
("cfg", ";"),
|
||||
("conf", "#"),
|
||||
("dockerfile", "#"),
|
||||
("makefile", "#"),
|
||||
("cmake", "#"),
|
||||
];
|
||||
|
||||
pub struct CommentDetector {
|
||||
pub default_style: CommentStyle,
|
||||
style_map: HashMap<String, CommentStyle>,
|
||||
}
|
||||
|
||||
impl CommentDetector {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
let style_map = DEFAULT_STYLES
|
||||
.iter()
|
||||
.map(|&(filetype, prefix)| return (filetype.to_string(), CommentStyle::new(prefix.to_string())))
|
||||
.collect();
|
||||
|
||||
return Self {
|
||||
default_style: CommentStyle::new("#".to_string()),
|
||||
style_map,
|
||||
};
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn detect_from_filename(&self, filename: &str) -> &CommentStyle {
|
||||
let ext = filename.rsplit('.').next().unwrap_or_default().to_lowercase();
|
||||
return self.style_map.get(&ext).unwrap_or(&self.default_style);
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn detect_from_filetype(&self, filetype: &str) -> &CommentStyle {
|
||||
let filetype = filetype.to_lowercase();
|
||||
return self.style_map.get(&filetype).unwrap_or(&self.default_style);
|
||||
}
|
||||
|
||||
pub fn load_config(&mut self, config: &Config) {
|
||||
for (filetype, prefix) in &config.comment_styles {
|
||||
self.style_map.insert(filetype.clone(), CommentStyle::new(prefix.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CommentDetector {
|
||||
fn default() -> Self {
|
||||
return Self::new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use dirs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
pub comment_styles: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
return Self { comment_styles: HashMap::new() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Loads the configuration from the user's config directory, or returns the default when no file exists.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the config file cannot be read or is not valid YAML.
|
||||
pub fn load() -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let config_path = Self::get_config_path();
|
||||
|
||||
if config_path.exists() {
|
||||
let content = std::fs::read_to_string(&config_path)?;
|
||||
let config: Self = serde_yaml::from_str(&content)?;
|
||||
return Ok(config);
|
||||
} else {
|
||||
return Ok(Self::default());
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_config_path() -> PathBuf {
|
||||
let mut config_dir = dirs::config_dir().unwrap_or_else(|| return PathBuf::from("."));
|
||||
config_dir.push("kfmtbox");
|
||||
config_dir.push("comments.yaml");
|
||||
return config_dir;
|
||||
}
|
||||
|
||||
/// Writes the configuration to the user's config directory, creating it if needed.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the directory or file cannot be written, or the config cannot be serialized.
|
||||
pub fn save(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let config_path = Self::get_config_path();
|
||||
|
||||
// Create config directory if it doesn't exist
|
||||
if let Some(parent) = config_path.parent() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
|
||||
let content = serde_yaml::to_string(self)?;
|
||||
std::fs::write(&config_path, content)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
pub mod box_renderer;
|
||||
pub mod cli;
|
||||
pub mod comment_detector;
|
||||
pub mod config;
|
||||
pub mod text_wrapper;
|
||||
pub mod verbose;
|
||||
|
||||
pub use box_renderer::BoxRenderer;
|
||||
pub use cli::Cli;
|
||||
pub use comment_detector::CommentDetector;
|
||||
pub use config::Config;
|
||||
pub use text_wrapper::TextWrapper;
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
use std::io::{self, Read};
|
||||
|
||||
use clap::Parser;
|
||||
use kfmtbox::verbose::{set_verbose, verbose_msg};
|
||||
use kfmtbox::{BoxRenderer, Cli, CommentDetector, Config};
|
||||
|
||||
/// Main entry point for the kfmtbox application.
|
||||
///
|
||||
/// Reads text from stdin, formats it as a flower box comment, and outputs to stdout.
|
||||
/// The comment style is determined by the file type specified via command line arguments.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if:
|
||||
/// - Input cannot be read from stdin
|
||||
/// - Configuration file cannot be loaded or parsed
|
||||
/// - Output cannot be written to stdout
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
set_verbose(cli.verbose);
|
||||
|
||||
// Load configuration
|
||||
verbose_msg("Loading Config");
|
||||
let config = Config::load().unwrap_or_else(|_| return Config::default());
|
||||
|
||||
// Initialize comment detector
|
||||
verbose_msg("Detecting Comment Type");
|
||||
let mut detector = CommentDetector::new();
|
||||
detector.load_config(&config);
|
||||
|
||||
// Determine comment style
|
||||
let comment_style = if let Some(filename) = &cli.filename {
|
||||
detector.detect_from_filename(filename).clone()
|
||||
} else if let Some(filetype) = &cli.filetype {
|
||||
detector.detect_from_filetype(filetype).clone()
|
||||
} else {
|
||||
detector.default_style.clone()
|
||||
};
|
||||
|
||||
// Read input from stdin
|
||||
verbose_msg("Reading Comment from STDIN");
|
||||
let mut input = String::new();
|
||||
io::stdin().read_to_string(&mut input)?;
|
||||
|
||||
// Remove trailing newline if present and normalize line endings
|
||||
verbose_msg("Cleaning Comment (Removing Newlines and Returns");
|
||||
let input = input.trim_end();
|
||||
let input = input.replace("\r\n", "\n").replace("\n\r", "\n").replace('\r', "\n");
|
||||
|
||||
if input.is_empty() {
|
||||
verbose_msg("Input was empty - returning nothing successfully");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Create box renderer and render the flower box
|
||||
verbose_msg("Rendering comment in new flower box");
|
||||
let renderer = BoxRenderer::new(comment_style, cli.max_width);
|
||||
let result = renderer.render_flower_box(&input);
|
||||
|
||||
// Output to stdout
|
||||
verbose_msg("Outputting rendered comment");
|
||||
println!("{result}");
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
pub struct TextWrapper {
|
||||
max_width: usize,
|
||||
}
|
||||
|
||||
impl TextWrapper {
|
||||
#[must_use]
|
||||
pub const fn new(max_width: usize) -> Self {
|
||||
return Self { max_width };
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn wrap_text(&self, text: &str) -> Vec<String> {
|
||||
// First, split by newlines to preserve existing line breaks
|
||||
let input_lines: Vec<&str> = text.split('\n').collect();
|
||||
let mut all_lines = Vec::new();
|
||||
|
||||
for line in input_lines {
|
||||
let words: Vec<&str> = line.split_whitespace().collect();
|
||||
if words.is_empty() {
|
||||
all_lines.push(String::new());
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut current_line = String::new();
|
||||
|
||||
for word in words {
|
||||
let test_line = if current_line.is_empty() { word.to_string() } else { format!("{current_line} {word}") };
|
||||
|
||||
// Use a smaller effective width for better wrapping
|
||||
let effective_width = 20; // Force wrapping at 20 characters
|
||||
if test_line.len() <= effective_width {
|
||||
current_line = test_line;
|
||||
} else {
|
||||
if !current_line.is_empty() {
|
||||
all_lines.push(current_line);
|
||||
}
|
||||
current_line = word.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
if !current_line.is_empty() {
|
||||
all_lines.push(current_line);
|
||||
}
|
||||
}
|
||||
|
||||
if all_lines.is_empty() {
|
||||
return vec![String::new()];
|
||||
}
|
||||
|
||||
return all_lines;
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn balance_lines(&self, lines: Vec<String>) -> Vec<String> {
|
||||
if lines.len() <= 1 {
|
||||
return lines;
|
||||
}
|
||||
|
||||
let total_chars: usize = lines.iter().map(|line| return line.len()).sum();
|
||||
let avg_chars_per_line = total_chars.checked_div(lines.len()).unwrap_or(0);
|
||||
let target_width = usize::midpoint(avg_chars_per_line, self.max_width);
|
||||
let max_combined_width = 25; // Don't combine lines if result would be longer than 25 chars
|
||||
|
||||
let mut balanced = Vec::new();
|
||||
let mut current_line = String::new();
|
||||
|
||||
for line in lines {
|
||||
if current_line.is_empty() {
|
||||
current_line = line;
|
||||
} else {
|
||||
let test_line = format!("{current_line} {line}");
|
||||
if test_line.len() <= target_width && test_line.len() <= max_combined_width {
|
||||
current_line = test_line;
|
||||
} else {
|
||||
balanced.push(current_line);
|
||||
current_line = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !current_line.is_empty() {
|
||||
balanced.push(current_line);
|
||||
}
|
||||
|
||||
return balanced;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if an assertion fails.
|
||||
#[test]
|
||||
fn test_wrap_text() {
|
||||
let wrapper = TextWrapper::new(20);
|
||||
let text = "This is a very long line that should be wrapped into multiple lines";
|
||||
let result = wrapper.wrap_text(text);
|
||||
|
||||
assert!(result.len() > 1);
|
||||
for line in &result {
|
||||
assert!(line.len() <= 20);
|
||||
}
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if an assertion fails.
|
||||
#[test]
|
||||
fn test_balance_lines() {
|
||||
let wrapper = TextWrapper::new(20);
|
||||
let lines = vec!["Short".to_string(), "Very long line that exceeds".to_string(), "Another short".to_string()];
|
||||
let result = wrapper.balance_lines(lines);
|
||||
|
||||
assert_eq!(result.len(), 3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
// global flag
|
||||
pub static IS_VERBOSE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
// set from anywhere
|
||||
pub fn set_verbose(on: bool) {
|
||||
IS_VERBOSE.store(on, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// read from anywhere
|
||||
pub fn is_verbose() -> bool {
|
||||
return IS_VERBOSE.load(Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn verbose_msg(msg: &str) {
|
||||
if !is_verbose() {
|
||||
return;
|
||||
}
|
||||
|
||||
println!("[VERBOSE] {msg}");
|
||||
}
|
||||
|
||||
pub fn verbose_value<T: std::fmt::Debug>(label: &str, val: T) {
|
||||
if !is_verbose() {
|
||||
return;
|
||||
}
|
||||
|
||||
println!("[VERBOSE] {label} = {val:?}");
|
||||
}
|
||||
Reference in new issue
Block a user