fn apply_files(
    state_list: Vec<PortalMapping>,
    manifest: &mut Manifest,
    old_files: &mut Vec<PathBuf>,
) -> anyhow::Result<()> {
    let mut hash_cache: HashMap<PathBuf, String> = HashMap::new();
    let mut new_state_list = Vec::new();

    for state in state_list {
        let (push, prune) = if matches!(state.target.try_exists(), Ok(true)) {
            let mut target_hash = String::new();
            let already_matches = match state.file_type {
                FileType::Link => is_matching_symlink(&state.target, &state.source),
                FileType::Copy => {
                    state.target.is_file() && !state.target.is_symlink() && {
                        target_hash = calculate_file_hash(&state.target)?;
                        &target_hash
                    } == {
                        if let Some(cache) = hash_cache.get(&state.source) {
                            #[cfg(test)]
                            CACHE.set(CACHE.get() + 1);
                            cache
                        } else {
                            calculate_file_hash(&state.source).map(|h| {
                                hash_cache.insert(state.source.clone(), h);
                                hash_cache.get(&state.source).unwrap()
                            })?
                        }
                    }
                }
            };

            if already_matches {
                #[cfg(test)]
                DO_NOTHING.set(true);

                (false, true)
            } else {
                let is_managed = match manifest.inner.get(&state.target) {
                    Some(ManifestType::Link { source }) => {
                        is_matching_symlink(&state.target, source)
                    }
                    Some(ManifestType::Copy { hash }) => {
                        let h = if target_hash.is_empty() {
                            calculate_file_hash(&state.target)?
                        } else {
                            target_hash
                        };
                        h == *hash
                    }
                    _ => false,
                };

                if is_managed {
                    (true, true)
                } else {
                    #[cfg(test)]
                    {
                        PROMPT.set(true);
                        (OVERWRITE.get(), false)
                    }
                    #[cfg(not(test))]
                    {
                        use crate::prompt::{Prompt, PromptError};

                        (
                            match Prompt::new(
                                format!("{} already exists", &state.target.display()),
                                "overwrite",
                            )
                            .options(vec![('o', "overwrite"), ('s', "skip"), ('q', "quit")])
                            .print()
                            .map_err(PromptError::Io)?
                            {
                                "overwrite" => true,
                                "skip" => false,
                                "quit" => anyhow::bail!(PromptError::Quit),
                                _ => unreachable!(),
                            },
                            false,
                        )
                    }
                }
            }
        } else {
            (true, false)
        };

        if prune {
            if let Some(i) = old_files.iter().position(|p| p == &state.target) {
                old_files.swap_remove(i);
            }
        }
        if push {
            new_state_list.push(state);
        }
    }

    fn remove_path(path: &Path) {
        if matches!(path.try_exists(), Ok(false)) {
            return;
        }
        let result = if path.is_dir() {
            remove_dir_all(path)
        } else {
            remove_file(path)
        };
        if let Err(e) = result {
            log::error!("Failed to remove {}: {}", path.display(), e);
        };
    }

    for state in new_state_list {
        if let Some(parent) = state.target.parent() {
            if let Err(e) = create_dir_all(parent) {
                log::error!(
                    "Failed to create parent directory for {}: {}",
                    state.target.display(),
                    e
                );
                continue;
            }
        }

        match state.file_type {
            FileType::Link => {
                remove_path(&state.target);
                if let Err(e) = symlink(&state.source, &state.target) {
                    log::error!(
                        "Failed to create symlink {}: {}",
                        &state.target.display(),
                        e
                    );
                } else {
                    manifest.inner.insert(
                        state.target.clone(),
                        ManifestType::Link {
                            source: state.source.to_path_buf(),
                        },
                    );
                };
            }
            FileType::Copy => {
                remove_path(&state.target);
                if let Err(e) = copy(&state.source, &state.target) {
                    log::error!("Failed to copy file {}: {}", &state.target.display(), e);
                } else {
                    let hash = if let Some(s) = hash_cache.get(&state.source) {
                        #[cfg(test)]
                        CACHE.set(CACHE.get() + 1);

                        s.to_string()
                    } else {
                        match calculate_file_hash(&state.source) {
                            Ok(hash) => {
                                hash_cache.insert(state.source, hash.clone());
                                hash
                            }
                            Err(e) => {
                                log::error!("{e}");
                                String::new()
                            }
                        }
                    };
                    manifest
                        .inner
                        .insert(state.target, ManifestType::Copy { hash });
                }
            }
        }
    }

    Ok(())
}

give this function a better name