Created
September 16, 2022 16:09
-
-
Save connorfuhrman/f67643a036b47ec2419c3ee6263885d1 to your computer and use it in GitHub Desktop.
C code for a nicely trimmed working directory string to be used in shell prompt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Program to display the current working directory but ensure that the string | |
// does not take up more than half of the current terminal window size | |
// | |
// Compile as gcc prompt_dir.c -o prompt_dir_str -Wall -Wextra -pedantic -std=c11 -ltermcap -O3 | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <linux/limits.h> | |
#include <termcap.h> | |
#include <error.h> | |
#ifndef WIDTH_PERCENTAGE_DEFAULT | |
#define WIDTH_PERCENTAGE_DEFAULT 0.35 | |
#endif | |
// Function to advance a pointer to the next '/' char in | |
// a string. | |
// Returns a pointer to the '/' char if succesfull | |
// Returns NULL if there is no next slash | |
static char* next_slash(const char* restrict path) { | |
while(path) { | |
const char curr = *path; | |
if (curr == '/') return (char*)path; | |
else ++path; | |
} | |
return NULL; | |
} | |
static char* prev_slash(const char* restrict path) { | |
while(path) { | |
const char curr = *path; | |
if (curr == '/') return (char*)path; | |
else --path; | |
} | |
return NULL; | |
} | |
// Rule (1) function: | |
// Always print the first and last directories with a ... in the middle | |
static void rule1(const char* full_cwd, char* to_print) { | |
// Get only the first directory name plus the slash itself | |
char* first_slash = next_slash(full_cwd); | |
strncpy(to_print, full_cwd, (first_slash-full_cwd+1)/sizeof(char)); | |
// append '.../' and the current local dir | |
strcat(to_print, ".../"); | |
char* local_dir = prev_slash(full_cwd + strlen(full_cwd))+1; | |
strcat(to_print, local_dir); | |
} | |
int main(int argc, char** argv) { | |
// Get the percentage of allowed screen width in the path prompt | |
// which defualts to WIDTH_PERCENTAGE_DEFAULT | |
double width_percentage = (argc == 2) ? atof(argv[1]) : WIDTH_PERCENTAGE_DEFAULT; | |
// Get the full working directory path | |
char* cwd = NULL; | |
char cwd_buf[PATH_MAX] = {0}; | |
if (!getcwd(cwd_buf, PATH_MAX)) { | |
fprintf(stderr, "ERROR: [prompt_dir_str] cannot get current working directory\n"); | |
goto exit; | |
} | |
cwd = cwd_buf; | |
// Get the width of the terminal | |
char* termtype = getenv("TERM"); | |
char termbuf[2048] = {0}; | |
if (tgetent(termbuf, termtype) < 0) { | |
fprintf(stderr, "ERROR: [prompt_dir_str] Could not access the termcap database.\n"); | |
goto exit; | |
} | |
int term_width = tgetnum("co"); | |
size_t allowable_width = (size_t)(width_percentage*(double)term_width); | |
// Check if cwd is a sub-dir of $HOME | |
char* home_dir = getenv("HOME"); | |
if (!home_dir) { | |
fprintf(stderr, "ERROR: [prompt_dir_str] Can not get HOME directory\n"); | |
goto exit; | |
} | |
if (strstr(cwd, home_dir)) { | |
// then home_dir is substring of cwd so overwrite the last char of the home dir | |
const size_t offset = strlen(home_dir)-1; | |
cwd[offset] = '~'; | |
cwd += offset; | |
} | |
// Print a string of appropriate length | |
if (strlen(cwd) <= allowable_width) { | |
// Whole string can be printed | |
puts(cwd); | |
} | |
else { | |
// Print the allowable number of characters to stdout. | |
// The the following: | |
// ~/dir/.../dir/cwd | |
// /dir/.../dir/cwd | |
// /.../dir/cwd | |
// /.../cwd | |
char to_print[allowable_width]; | |
memset(to_print, 0, allowable_width*sizeof(char)); | |
// Rule (1): | |
rule1(cwd, to_print); | |
puts(to_print); | |
} | |
exit: | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment