diff options
| -rwxr-xr-x | a | 21 | ||||
| -rwxr-xr-x | create_c_project.py | 647 | ||||
| -rwxr-xr-x | dev-tmux | 10 | ||||
| -rwxr-xr-x | sisc | 45 | ||||
| -rwxr-xr-x | tmux-cmd | 3 |
5 files changed, 726 insertions, 0 deletions
@@ -0,0 +1,21 @@ +#!/bin/sh + +export SHELL="/bin/zsh" +export acmeshell="/bin/zsh" +export BROWSER=safari +export tabstop=2 +export TERM=dumb +export PAGER=nobs + +if [ "$(pgrep plumber)" ]; then + echo plumber is running +else + echo starting plumber + plumber +fi + +export NODE_NO_READLINE=1 + +export PATH="/usr/bin:/bin:/usr/sbin:/sbin:$PATH" + +acme -a -b -c 2 -f /mnt/font/JetBrainsMono-Medium/16a/font $1 diff --git a/create_c_project.py b/create_c_project.py new file mode 100755 index 0000000..b3ba6dd --- /dev/null +++ b/create_c_project.py @@ -0,0 +1,647 @@ +#!/usr/bin/env python3 +""" +Create a C project structure based on the gcli build system pattern. +Simplified version with minimal files. +""" + +import argparse +import os +import sys +from pathlib import Path +import urllib.request + + +def create_configure_script(project_name, version): + """Generate a configure script.""" + return f'''#!/usr/bin/env sh +# +# Configure script for {project_name} +# + +CONFIGURE_CMD_ARGS="${{*}}" + +PACKAGE_VERSION="{version}" +PACKAGE_DATE="$(date +%Y-%m-%d)" +PACKAGE_STRING="{project_name} $PACKAGE_VERSION" +PACKAGE_BUGREPORT="your-email@example.com" +PACKAGE_URL="https://example.com/{project_name}" + +find_program() {{ + varname=$1 + shift + + printf "Checking for $varname ..." >&2 + for x in $*; do + if command -v $x >/dev/null 2>&1 && [ -x $(command -v $x) ]; then + binary="$(command -v $x)" + printf " $binary\\n" >&2 + echo "${{binary}}" + return 0 + fi + done + printf " not found\\n" >&2 + return 1 +}} + +die() {{ + printf "%s\\n" "${{*}}" + exit 1 +}} + +# Default values +PREFIX="/usr/local" +OPTIMISE="release" +CC="" +AR="ar" +RANLIB="ranlib" +RM="rm" +INSTALL="install" + +# Parse arguments +while [ $# -gt 0 ]; do + case "$1" in + --prefix=*) + PREFIX="${{1#--prefix=}}" + ;; + --prefix) + shift + PREFIX="$1" + ;; + --debug) + OPTIMISE="debug" + ;; + --release) + OPTIMISE="release" + ;; + --help) + cat <<EOF +Configure script for {project_name} + +Options: + --prefix=PREFIX Installation prefix (default: /usr/local) + --debug Build with debug symbols, no optimization + --release Build with optimizations (default) + --help Show this help message + +Environment variables: + CC C compiler + AR Archiver + RANLIB ranlib + CFLAGS Additional C flags + LDFLAGS Additional linker flags +EOF + exit 0 + ;; + *) + die "Unknown option: $1" + ;; + esac + shift +done + +# Find required tools +if [ -z "$CC" ]; then + CC=$(find_program CC cc clang gcc) || die "No C compiler found" +fi + +# Use basename only for better tool compatibility (e.g., bear) +CC=$(basename "$CC") + +# Detect compiler type +if $CC --version 2>&1 | grep -i clang >/dev/null; then + CCOM="clang" +elif $CC --version 2>&1 | grep -i gcc >/dev/null; then + CCOM="gcc" +else + CCOM="unknown" +fi + +printf "Compiler: %s (%s)\\n" "$CC" "$CCOM" + +# Generate config.h +cat > config.h <<EOF_CONFIG +#ifndef CONFIG_H +#define CONFIG_H + +#define PACKAGE_VERSION "$PACKAGE_VERSION" +#define PACKAGE_STRING "$PACKAGE_STRING" +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +#define PACKAGE_URL "$PACKAGE_URL" + +#endif /* CONFIG_H */ +EOF_CONFIG + +# Determine source directory +SRCDIR="$(dirname "$0")" +SRCDIR="$(cd "$SRCDIR" && pwd)" + +# Generate Makefile from Makefile.in +sed \\ + -e "s|@PREFIX@|$PREFIX|g" \\ + -e "s|@CC@|$CC|g" \\ + -e "s|@CCOM@|$CCOM|g" \\ + -e "s|@AR@|$AR|g" \\ + -e "s|@RANLIB@|$RANLIB|g" \\ + -e "s|@RM@|$RM|g" \\ + -e "s|@INSTALL@|$INSTALL|g" \\ + -e "s|@OPTIMISE@|$OPTIMISE|g" \\ + -e "s|@VERSION@|$PACKAGE_VERSION|g" \\ + -e "s|@SRCDIR@|$SRCDIR|g" \\ + < "$SRCDIR/Makefile.in" > Makefile + +echo "Configuration complete. Run 'make' to build." +''' + + +def create_makefile_in(project_name): + """Generate a Makefile.in template.""" + return f'''# Makefile for {project_name} +VERSION = @VERSION@ + +# Environment and values saved by the configure script +CC = @CC@ +CCOM = @CCOM@ +AR = @AR@ +RANLIB = @RANLIB@ +RM = @RM@ +INSTALL = @INSTALL@ +OPTIMISE = @OPTIMISE@ +PREFIX = @PREFIX@ +SRCDIR = @SRCDIR@ + +# Find all .c files in src/ recursively +SRCS := $(shell find $(SRCDIR)/src -name '*.c' -type f) +# Generate object file names (strip SRCDIR/src/ prefix and change .c to .o) +OBJS := $(patsubst $(SRCDIR)/src/%.c,%.o,$(SRCS)) + +# VPATH for finding source files +VPATH = $(SRCDIR)/src:$(shell find $(SRCDIR)/src -type d 2>/dev/null | tr '\\n' ':') + +# Compiler flags +COPTFLAGS_gcc_debug = -O0 -g3 -Wall -Wextra +COPTFLAGS_gcc_release = -O2 -DNDEBUG +COPTFLAGS_clang_debug = -O0 -g3 -Wall -Wextra +COPTFLAGS_clang_release = -O2 -DNDEBUG +COPTFLAGS = $(COPTFLAGS_$(CCOM)_$(OPTIMISE)) + +CSTDFLAGS_gcc = -std=c11 -pedantic +CSTDFLAGS_clang = -std=c11 -pedantic +CSTDFLAGS = $(CSTDFLAGS_$(CCOM)) + +CFLAGS = $(CSTDFLAGS) $(COPTFLAGS) -I$(SRCDIR)/include -I$(SRCDIR)/thirdparty/utest -I. -DHAVE_CONFIG_H=1 +LDFLAGS = + +# Targets +BINARY = {project_name} + +.PHONY: all clean install check + +all: $(BINARY) + +# Create subdirectories for object files if needed +$(BINARY): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) + +# Suffix rule for compiling (uses VPATH to find .c files) +.SUFFIXES: .c .o + +.c.o: + @test -d $(dir $@) || mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + $(RM) -f $(BINARY) $(OBJS) + $(RM) -f test_main test_main.o + find . -type f -name '*.o' -delete 2>/dev/null || true + +install: $(BINARY) + $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin + $(INSTALL) -m 755 $(BINARY) $(DESTDIR)$(PREFIX)/bin/ + +# Test target - links with all objects except main.o +TEST_OBJS := $(filter-out main.o,$(OBJS)) + +check: test_main + ./test_main + +test_main: test_main.o $(TEST_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ + +test_main.o: $(SRCDIR)/tests/test_main.c $(SRCDIR)/include/{project_name}/base.h + $(CC) $(CFLAGS) -c -o $@ $< + +''' + + +def create_main_c(project_name): + """Generate a main.c file.""" + return f'''#include <stdio.h> +#include <stdlib.h> +#include "{project_name}/base.h" +#include "config.h" + +int main(int argc, char **argv) {{ + (void)argc; + (void)argv; + + printf("%s version %s\\n", PACKAGE_STRING, PACKAGE_VERSION); + + /* Call a function from base.h */ + {project_name}_init(); + + printf("Hello from {project_name}!\\n"); + + {project_name}_cleanup(); + + return 0; +}} +''' + + +def create_base_c(project_name): + """Generate a base.c implementation file.""" + return f'''#include "{project_name}/base.h" + +void {project_name}_init(void) {{ + /* Initialize resources here */ +}} + +void {project_name}_cleanup(void) {{ + /* Cleanup resources here */ +}} +''' + + +def create_base_h(project_name): + """Generate a base.h header file.""" + guard = f"{project_name.upper()}_BASE_H" + return f'''#ifndef {guard} +#define {guard} + +/** + * Initialize {project_name} + */ +void {project_name}_init(void); + +/** + * Cleanup {project_name} resources + */ +void {project_name}_cleanup(void); + +#endif /* {guard} */ +''' + + +def create_test_c(project_name): + """Generate a test file using utest.h.""" + return f'''#include "utest.h" +#include "{project_name}/base.h" + +UTEST({project_name}, init_cleanup) {{ + {project_name}_init(); + {project_name}_cleanup(); + ASSERT_TRUE(1); +}} + +UTEST({project_name}, basic_test) {{ + ASSERT_EQ(1, 1); + ASSERT_NE(1, 0); + ASSERT_TRUE(1); + ASSERT_FALSE(0); +}} + +UTEST_MAIN() +''' + + +def create_readme(project_name, version): + """Generate a README.md file.""" + return f'''# {project_name.upper()} + +Version {version} + +## Description + +A C project created with the gcli-style build system. + +## Building + +### Dependencies + +Required: +- C11 compiler (gcc or clang) +- make + +### Build Instructions + +```bash +./configure +make +``` + +### Debug Build + +```bash +./configure --debug +make +``` + +### Out-of-tree builds (optional) + +You can also build in a separate directory: + +```bash +mkdir build +cd build +../configure +make +``` + +### Installation + +```bash +sudo make install +``` + +Default prefix is `/usr/local`. To change: + +```bash +./configure --prefix=/usr +``` + +## Testing + +```bash +make check +``` + +## IDE Support + +### clangd / LSP + +To generate `compile_commands.json` for clangd, use one of these methods: + +**Option 1: Using compiledb (recommended)** +```bash +pip install compiledb +compiledb make +``` + +**Option 2: Using bear** +```bash +bear -- make +``` + +If the file is empty, try a clean build: +```bash +make clean +bear -- make +``` + +## Usage + +```bash +./{project_name} +``` +''' + + +def create_gitignore(): + """Generate a .gitignore file.""" + return '''# Build artifacts +*.o +*.a +*.so +*.dylib +*.dll +*.exe + +# Build directories +build/ +debug/ +release/ +dist/ + +# Generated files +config.h +Makefile + +# Editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db +''' + + +def create_clangd_config(): + """Generate a .clangd configuration file.""" + return '''# clangd configuration +CompileFlags: + Add: + - -Wall + - -Wextra + +Diagnostics: + UnusedIncludes: Strict + MissingIncludes: Strict +''' + + +def create_license(project_name): + """Generate a simple LICENSE file.""" + import datetime + year = datetime.datetime.now().year + return f'''Copyright (c) {year}, {project_name} authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +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. +''' + + +def create_gentarball_sh(project_name): + """Generate a gentarball.sh script for creating release tarballs.""" + return f'''#!/bin/sh +# +# Generate release tarballs for {project_name} + +command -v git > /dev/null 2>&1 || (echo "error: you need git to run this script" && exit 1) + +findversion() {{ + eval $(grep PACKAGE_VERSION $(dirname $0)/../configure | sed 1q) + echo $PACKAGE_VERSION +}} + +VERSION=$(findversion) + +DIR=dist/{project_name}-${{VERSION}} +mkdir -p $DIR + +if [ -d .got ]; then + repodir=$(got info | grep '^repository' | cut -d: -f2 | xargs) + head=$(got br) +else + repodir=$(git rev-parse --show-toplevel)/.git + head=@ +fi + +echo "Making BZIP tarball" +git --git-dir="${{repodir}}" archive --format=tar --prefix={project_name}-$VERSION/ $head \\ + | bzip2 -v > $DIR/{project_name}-$VERSION.tar.bz2 +echo "Making XZ tarball" +git --git-dir="${{repodir}}" archive --format=tar --prefix={project_name}-$VERSION/ $head \\ + | xz -v > $DIR/{project_name}-$VERSION.tar.xz +echo "Making GZIP tarball" +git --git-dir="${{repodir}}" archive --format=tar --prefix={project_name}-$VERSION/ $head \\ + | gzip -v > $DIR/{project_name}-$VERSION.tar.gz + +( + cd $DIR + echo "Calculating SHA256SUMS" + sha256sum *.tar* > SHA256SUMS +) + +echo "Release Tarballs are at $DIR" +''' + + +def create_project(project_name, version, output_dir): + """Create the complete project structure.""" + project_path = Path(output_dir) / project_name + + if project_path.exists(): + print(f"Error: Directory {project_path} already exists!", file=sys.stderr) + return False + + print(f"Creating project: {project_name} v{version}") + print(f"Output directory: {project_path}") + + # Create directory structure + dirs = [ + project_path, + project_path / "src", + project_path / "include" / project_name, + project_path / "tests", + project_path / "thirdparty" / "utest", + project_path / "tools", + ] + + for dir_path in dirs: + dir_path.mkdir(parents=True, exist_ok=True) + print(f" Created: {dir_path.relative_to(output_dir)}/") + + # Create files + files = { + project_path / "configure": create_configure_script(project_name, version), + project_path / "Makefile.in": create_makefile_in(project_name), + project_path / "src" / "main.c": create_main_c(project_name), + project_path / "src" / "base.c": create_base_c(project_name), + project_path / "include" / project_name / "base.h": create_base_h(project_name), + project_path / "tests" / "test_main.c": create_test_c(project_name), + project_path / "tools" / "gentarball.sh": create_gentarball_sh(project_name), + project_path / "README.md": create_readme(project_name, version), + project_path / ".gitignore": create_gitignore(), + project_path / ".clangd": create_clangd_config(), + project_path / "LICENSE": create_license(project_name), + } + + for file_path, content in files.items(): + file_path.write_text(content) + print(f" Created: {file_path.relative_to(output_dir)}") + + # Download utest.h + print(" Downloading utest.h...") + utest_url = "https://raw.githubusercontent.com/sheredom/utest.h/master/utest.h" + utest_path = project_path / "thirdparty" / "utest" / "utest.h" + try: + with urllib.request.urlopen(utest_url) as response: + utest_content = response.read().decode('utf-8') + utest_path.write_text(utest_content) + print(f" Created: {utest_path.relative_to(output_dir)}") + except Exception as e: + print(f" Warning: Could not download utest.h: {e}", file=sys.stderr) + print(f" You can manually download it from {utest_url}", file=sys.stderr) + + # Make configure executable + (project_path / "configure").chmod(0o755) + (project_path / "tools" / "gentarball.sh").chmod(0o755) + + print(f"\\n✓ Project created successfully!") + print(f"\\nNext steps:") + print(f" cd {project_path}") + print(f" ./configure") + print(f" make") + print(f" ./{project_name}") + + return True + + +def main(): + parser = argparse.ArgumentParser( + description="Create a C project with gcli-style build system", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + %(prog)s myproject + %(prog)s myproject --version 0.1.0 + %(prog)s myproject --output ~/projects + """ + ) + + parser.add_argument( + "name", + help="Project name (lowercase, no spaces)" + ) + + parser.add_argument( + "--version", + default="0.1.0", + help="Initial version number (default: 0.1.0)" + ) + + parser.add_argument( + "--output", + default=".", + help="Output directory (default: current directory)" + ) + + args = parser.parse_args() + + # Validate project name + if not args.name.replace("_", "").replace("-", "").isalnum(): + print("Error: Project name must contain only letters, numbers, hyphens, and underscores", + file=sys.stderr) + return 1 + + if not args.name.islower(): + print("Warning: Project name should be lowercase", file=sys.stderr) + + # Create the project + if create_project(args.name, args.version, args.output): + return 0 + else: + return 1 + + +if __name__ == "__main__": + sys.exit(main())
\ No newline at end of file diff --git a/dev-tmux b/dev-tmux new file mode 100755 index 0000000..e0ac529 --- /dev/null +++ b/dev-tmux @@ -0,0 +1,10 @@ +#!/bin/bash + +SESSION_NAME=${1:- } + +tmux new-session -d -s "$SESSION_NAME" -n vi +tmux new-window -t "$SESSION_NAME" -n build +tmux new-window -t "$SESSION_NAME" -n git +tmux new-window -t "$SESSION_NAME" -n nix +tmux select-window -t "$SESSION_NAME":vi +tmux attach-session -t "$SESSION_NAME" @@ -0,0 +1,45 @@ +#!/bin/sh + +# Some weird script to find a word + +if [ $# -lt 1 ]; then + echo "Usage: $0 <search_word> [search_directory] [ignored_dir1] [ignored_dir2] ..." >&2 + exit 1 +fi + +WORD="$1" +shift + +DIR="${1:-.}" +shift + +if [ ! -d "$DIR" ]; then + echo "Error: Directory '$DIR' does not exist." >&2 + exit 1 +fi + +IGNORED_DIRS="" +while [ $# -gt 0 ]; do + IGNORED_DIR="$1" + # Construct prune conditions + if [ -z "$IGNORED_DIRS" ]; then + IGNORED_DIRS="-path \"$DIR/$IGNORED_DIR\" -prune" + else + IGNORED_DIRS="$IGNORED_DIRS -o -path \"$DIR/$IGNORED_DIR\" -prune" + fi + shift +done + +if [ -n "$IGNORED_DIRS" ]; then + FIND_COMMAND="find \"$DIR\" $IGNORED_DIRS -o -type f -print" +else + FIND_COMMAND="find \"$DIR\" -type f" +fi + +eval "$FIND_COMMAND" | while read -r file; do + if grep -q "$WORD" "$file" 2>/dev/null; then + grep -n "$WORD" "$file" 2>/dev/null | while IFS=: read -r linenum line; do + printf "%s:%d - %s\n" "$file" "$linenum" "$(echo "$line" | sed 's/^ *//')" + done + fi +done diff --git a/tmux-cmd b/tmux-cmd new file mode 100755 index 0000000..cbaaac7 --- /dev/null +++ b/tmux-cmd @@ -0,0 +1,3 @@ +#/bin/sh + +tmux list-windows | grep -v "irc" | grep -v "email" | cut -d: -f1 | xargs -I{} tmux send-keys -t {} "$1" C-m |