1use std::path::{Path, PathBuf};
2
3use crate::{Candidate, CandidateMetadata};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum Action {
7 Open,
8 SwitchSession,
9 CreateOrSwitchSession,
10 OpenShellHere,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum CandidateAction {
15 Open,
16 SwitchSession,
17 CreateOrSwitchSession,
18 OpenShellHere,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum ResolvedAction {
23 SwitchSession {
24 session_name: String,
25 },
26 CreateOrSwitchSession {
27 session_name: String,
28 directory: PathBuf,
29 },
30 OpenShellHere {
31 directory: PathBuf,
32 },
33}
34
35#[must_use]
36pub fn resolve_action(candidate: &Candidate) -> Option<ResolvedAction> {
37 match (&candidate.action, &candidate.metadata) {
38 (CandidateAction::SwitchSession, CandidateMetadata::Session(metadata)) => {
39 Some(ResolvedAction::SwitchSession {
40 session_name: metadata.session_name.clone(),
41 })
42 }
43 (CandidateAction::CreateOrSwitchSession, CandidateMetadata::Directory(metadata)) => {
44 Some(ResolvedAction::CreateOrSwitchSession {
45 session_name: sanitize_session_name(&metadata.full_path),
46 directory: metadata.full_path.clone(),
47 })
48 }
49 (CandidateAction::OpenShellHere, CandidateMetadata::Directory(metadata)) => {
50 Some(ResolvedAction::OpenShellHere {
51 directory: metadata.full_path.clone(),
52 })
53 }
54 _ => None,
55 }
56}
57
58#[must_use]
59pub fn sanitize_session_name(path: &Path) -> String {
60 let raw_name = path
61 .file_name()
62 .and_then(|name| name.to_str())
63 .filter(|name| !name.is_empty())
64 .unwrap_or("wisp");
65
66 let sanitized: String = raw_name
67 .chars()
68 .map(|character| {
69 if character.is_ascii_alphanumeric() || matches!(character, '-' | '_') {
70 character
71 } else {
72 '-'
73 }
74 })
75 .collect();
76
77 let trimmed = sanitized.trim_matches('-');
78 if trimmed.is_empty() {
79 "wisp".to_string()
80 } else {
81 trimmed.to_string()
82 }
83}