Aller au contenu

Workspace Manager

Ce script m'a permis d'ajouter des commandes à mon terminal pour naviguer rapidement entre mes projets, les ouvrir dans mon IDE et lancer des actions contextuelles, avec le support de la recherche floue (fuzzy-search) et de l'autocomplétion.

Il est construit sur une architecture modulaire et agnostique : un Core universel gère les déplacements, et des Handlers spécifiques gèrent les commandes propres à chaque environnement.

Prérequis⚓︎

Pour que ce script fonctionne, les éléments suivants sont nécessaires :

  • Zsh : Le shell par défaut sur macOS.
  • fzf : L'outil de recherche floue interactif.
    brew install fzf
    
  • PhpStorm (ou autre IDE) : L'application doit être installée dans le dossier Applications et correctement nommée "PhpStorm" (le script utilise la commande native macOS open -a).

Arborescence⚓︎

Pour garder un système propre, j'ai séparé l'interface (couleurs et fonction d'affichage de message) de la logique métier dans un dossier personnalisé à la racine (~) :

.zsh_custom
├── ui.zsh
└── workspace.zsh

1. Le module d'interface (UI)⚓︎

Le fichier ~/.zsh_custom/ui.zsh contient :

~/.zsh_custom/ui.zsh
# UI et Helpers CLI

RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
BLUE="\033[0;34m"
CYAN="\033[0;36m"
RESET="\033[0m"

msg() {
  local color="$1"
  shift
  echo -e "${color}$*${RESET}"
}

2. Le script⚓︎

Le fichier ~/.zsh_custom/workspace.zsh contient la logique de gestion et de déplacement au sein des workspaces :

~/.zsh_custom/workspace.zsh
# CLI Workspace Manager
source "$HOME/.zsh_custom/ui.zsh"

select_project() {
  local workspace="$1"
  if ! command -v fzf >/dev/null 2>&1; then
    msg "$RED" "Aucun projet fourni et fzf introuvable."
    return 1
  fi

  # `! -name ".*"` pour exclure les dossiers cachés
  local selection=$(find "$workspace" -mindepth 1 -maxdepth 1 -type d ! -name ".*" -exec basename {} \; | fzf --height 40% --reverse --prompt="> ")
  echo "$selection"
}

_core_workspace_manager() {
  local cmd_name="$1"
  local workspace="$2"
  local ide_name="$3"
  local custom_handler="$4" # fonction qui gère les actions spécifiques
  shift 4

  local open_ide=false
  local project=""
  local custom_flags=() # tableau pour stocker les flags inconnus du core

  while [[ "$#" -gt 0 ]]; do
    case "$1" in
      -i|--ide)  
        open_ide=true; shift 
        ;;
      -h|--help)
        msg "$CYAN" "Usage: $cmd_name [options] [project]"
        echo
        msg "$CYAN" "Options globales :"
        echo "  -i, --ide     Ouvre le projet dans $ide_name"
        echo "  -h, --help    Affiche ce message"

        # On demande au handler d'afficher ses propres options d'aide
        if command -v "$custom_handler" >/dev/null 2>&1; then
           echo
           msg "$CYAN" "Options spécifiques :"
           "$custom_handler" "--help"
        fi
        return 0
        ;;
      -*) 
        # si le flag est inconnu du core, on le garde pour le handler
        custom_flags+=("$1")
        shift 
        ;;
      *)  
        project="$1"
        shift 
        ;;
    esac
  done

  # logique commune
  if [[ -z "$project" ]]; then
    project=$(select_project "$workspace") || return 1
  fi

  local dir="$workspace/$project"
  if [[ ! -d "$dir" ]]; then
    msg "$RED" "Projet introuvable: $project"
    return 1
  fi

  cd "$dir" || return
  msg "$CYAN" "Déplacement vers $(pwd)"

  if $open_ide; then
    msg "$CYAN" "Ouverture de $ide_name..."
    command -v open >/dev/null 2>&1 && open -a "$ide_name" "$dir" >/dev/null 2>&1 &
  fi

  # délégation des actions spécifiques restantes au handler
  if [[ ${#custom_flags[@]} -gt 0 ]] && command -v "$custom_handler" >/dev/null 2>&1; then
    "$custom_handler" "${custom_flags[@]}"
  fi
}




_work_handler() {
  for flag in "$@"; do
    case "$flag" in

      --help)    echo "  -s, --sync    Synchronise le code (ex: git pull)" ;;

      -s|--sync) msg "$CYAN" "Sync en cours..."; sync ;;

      *)         msg "$YELLOW" "Option ignorée par 'work': $flag" ;;

    esac
  done
}
work() { _core_workspace_manager "work" "/Volumes/Workspace" "PhpStorm" "_work_handler" "$@"; }
compdef '_files -W /Volumes/Workspace -/' work # (1)!




_dev_handler() {
  for flag in "$@"; do
    case "$flag" in

      --help)    
        echo "  -u, --up      Monte l'environnement Docker" 
        echo "  -s, --sync    Met à jour les packages NPM" 
        ;;

      -u|--up)
        msg "$CYAN" "Démarrage du projet..."; make up 
        ;;

      *)
        msg "$YELLOW" "Option ignorée par 'dev': $flag"
        ;;

    esac
  done
}
dev() { _core_workspace_manager "dev" "/Users/evan/dev" "PhpStorm" "_dev_handler" "$@"; }
compdef '_files -W /Users/evan/dev -/' dev # (1)!
  1. fonction native de Zsh qui signifie "Completion Define" (définir une complétion). Elle sert à lier une règle d'autocomplétion à une commande spécifique. En l'occurrence, _files est un utilitaire intégré à Zsh conçu spécialement pour générer des suggestions basées sur le système de fichiers.

3. Activation⚓︎

Il suffit de charger ce script dans le fichier de configuration principal de Zsh :

~/.zshrc
# ... reste du code 

source "$HOME/.zsh_custom/workspace.zsh"

Finalement, on recharge la configuration configuration :

source ~/.zshrc

Ajouter une nouvelle commande⚓︎

Grâce à l'architecture ouverte, il est possible de créer de nouvelles commandes en 3 étapes directement dans workspace.zsh, sans jamais toucher au cœur du script (_core_workspace_manager) :

  1. Créez une fonction handler _test_handler() { ... } pour définir les options spécifiques (voir ci-dessus).
  2. Déclarez la commande : test() { _core_workspace_manager "test" "/Chemin/Vers/Dossier" "NomIDE" "_test_handler" "$@"; }
  3. Ajoutez l'autocomplétion : compdef '_files -W /Chemin/Vers/Dossier -/' test

Utilisation⚓︎

L'outil fusionne des commandes globales (communes à tous les espaces) et des commandes spécifiques (propres au contexte).

Exemples d'utilisation :⚓︎

  • work : ouvre le menu interactif fzf pour choisir un projet.
  • work mon-projet : déplace directement dans le projet.
  • work -i mon-projet : déplace et ouvre le projet dans PhpStorm (Option Globale).

Options contextuelles :⚓︎

Les options varient selon la commande parente :

  • work -s mon-projet : Lance la fonction sync de l'espace de travail.
  • dev -u mon-projet : Lance une commande pour démarrer le server local de mon projet.
  • dev -s mon-projet : Refusera de lancer la fonction sync (puisque non définie ou différente dans le handler dev).

L'option --help (ou -h) affiche la liste des commandes universelles et spécifiques.