Skip to content

Instantly share code, notes, and snippets.

@connorfuhrman
Created September 16, 2022 16:09
Show Gist options
  • Save connorfuhrman/f67643a036b47ec2419c3ee6263885d1 to your computer and use it in GitHub Desktop.
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
// 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