Skip to content

Commit

Permalink
Add export configurations dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
1whatleytay committed Oct 5, 2023
1 parent a296ce5 commit 16bbb3a
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 74 deletions.
76 changes: 52 additions & 24 deletions src-tauri/src/auto_save.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
/*
use std::collections::HashSet;
use std::fs::File;
use std::path::PathBuf;
use std::sync::Mutex;
use notify::RecommendedWatcher;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use serde::{Deserialize, Serialize};
const AUTO_SAVE_VERSION: u32 = 1;
const AUTO_SAVE_FILENAME: &str = "save-state.json";
#[derive(Serialize, Deserialize)]
pub struct AutoSaveDetails {
version: u32,
files: Vec<PathBuf>
files: HashSet<PathBuf>
}
pub struct AutoSaveState {
Expand All @@ -18,26 +20,65 @@ pub struct AutoSaveState {
}
impl AutoSaveState {
pub fn new(app: tauri::AppHandle) -> AutoSaveState {
let watcher = notify::recommended_watcher(|event| {
fn watcher(app: tauri::AppHandle) -> Option<RecommendedWatcher> {
notify::recommended_watcher(move |event: Result<notify::Event, notify::Error>| {
let Ok(event) = event else { return };
match event.kind {
notify::EventKind::Create(kind) => { },
notify::EventKind::Remove(kind) => { },
notify::EventKind::Modify(kind) => { },
_ => {}
}
}).ok()
}
pub fn write_to(file: PathBuf) {
}
pub fn merge(&mut self, files: HashSet<PathBuf>) {
let removed = &self.details.files - &files;
let added = &files - &self.details.files;
}).ok();
if let Some(watcher) = &mut self.watcher {
for file in removed {
watcher.unwatch(&file).ok();
}
for file in added {
watcher.watch(&file, RecursiveMode::NonRecursive).ok();
}
}
self.details.files = files;
}
pub fn new(app: tauri::AppHandle) -> AutoSaveState {
AutoSaveState {
details: AutoSaveDetails {
version: AUTO_SAVE_VERSION,
files: vec![],
files: HashSet::new()
},
watcher
watcher: Self::watcher(app)
}
}
pub fn read_from_disc(app: tauri::AppHandle) -> AutoSaveState {
let path = tauri::api::path::app_data_dir(&app.config());
pub fn read_from_disc(app: tauri::AppHandle) -> Option<AutoSaveState> {
let mut path = tauri::api::path::app_data_dir(&app.config())?;
Self::new(app)
path.push(AUTO_SAVE_FILENAME);
let details: AutoSaveDetails = serde_json::from_reader(File::open(path).ok()?).ok()?;
Some(AutoSaveState {
details,
watcher: Self::watcher(app)
})
}
pub fn from_disc(app: tauri::AppHandle) -> AutoSaveState {
Self::read_from_disc(app.clone()).unwrap_or_else(|| Self::new(app))
}
}
Expand All @@ -46,17 +87,4 @@ pub struct AutoSaveFile {
path: String,
name: String
}
#[tauri::command]
pub fn register_files(files: Vec<String>, state: tauri::State<Mutex<AutoSaveState>>, app_handle: tauri::AppHandle) {
let mut pointer = state.lock().unwrap();
}
#[tauri::command]
pub fn get_files(state: tauri::State<Mutex<AutoSaveState>>) -> Vec<AutoSaveFile> {
let mut pointer = state.lock().unwrap();
vec![]
}
*/
52 changes: 49 additions & 3 deletions src-tauri/src/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::midi::forward_midi;
use crate::syscall::{ConsoleHandler, MidiHandler, SyscallState};
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::io::Cursor;
use std::path::PathBuf;
Expand Down Expand Up @@ -232,8 +232,52 @@ pub struct HexRegion {
pub data: String
}

#[derive(Deserialize)]
#[serde(rename_all="snake_case")]
pub enum AssembleRegionsKind {
Plain,
HexV3
}

#[derive(Deserialize)]
pub struct AssembleRegionsOptions {
pub kind: AssembleRegionsKind,
pub continuous: bool
}

#[tauri::command]
pub fn assemble_hex(text: &str, path: Option<&str>) -> (Option<Vec<HexRegion>>, AssemblerResult) {
pub fn assemble_regions_continuous(text: &str, path: Option<&str>, options: AssembleRegionsOptions) -> (Option<String>, AssemblerResult) {
let result = assemble_text(text, path);
let (binary, result) = AssemblerResult::from_result_with_binary(result, text);

let Some(binary) = binary else {
return (None, result)
};

let mut output: Vec<u8> = vec![];

for region in binary.regions {
if region.data.is_empty() {
continue
}

// Potential Overflow!
let end = region.address as usize + region.data.len();

if end > output.len() {
output.resize(end, 0);
}

output[region.address as usize .. end].copy_from_slice(&region.data);
};

let output = output.into_iter().map(|x| x as u64).collect();

(Some(encode_hex(output)), result)
}

#[tauri::command]
pub fn assemble_regions(text: &str, path: Option<&str>, options: AssembleRegionsOptions) -> (Option<Vec<HexRegion>>, AssemblerResult) {
let result = assemble_text(text, path);
let (binary, result) = AssemblerResult::from_result_with_binary(result, text);

Expand Down Expand Up @@ -266,9 +310,11 @@ pub fn assemble_hex(text: &str, path: Option<&str>) -> (Option<Vec<HexRegion>>,

let name = format!("{heading}_{address:x}_{flags}");

let data = region.data.iter().copied().map(|x| x as u64).collect();

HexRegion {
name,
data: encode_hex(region.data.iter().copied().map(|x| x as u64).collect())
data: encode_hex(data)
}
}).collect();

Expand Down
5 changes: 3 additions & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use tauri::WindowEvent::Destroyed;
use crate::display::{display_protocol, FlushDisplayBody, FlushDisplayState};
use crate::menu::{create_menu, handle_event};

use crate::build::{assemble, assemble_binary, assemble_hex, configure_asm, configure_elf, disassemble};
use crate::build::{assemble, assemble_binary, assemble_regions, assemble_regions_continuous, configure_asm, configure_elf, disassemble};
use crate::debug::{read_bytes, set_register, swap_breakpoints, write_bytes};
use crate::menu::platform_shortcuts;
use crate::midi::{midi_install, midi_protocol, MidiProviderContainer};
Expand Down Expand Up @@ -79,7 +79,8 @@ fn main() {
assemble, // build
disassemble, // build
assemble_binary, // build
assemble_hex, // build
assemble_regions, // build
assemble_regions_continuous, // build
configure_elf, // build
configure_asm, // build
resume, // execution
Expand Down
162 changes: 162 additions & 0 deletions src/components/ExportOverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<template>
<Modal :show="props.show" @close="emit('close')">
<div
class="max-w-2xl bg-neutral-900 rounded-xl px-8 py-6 mx-auto flex flex-col shadow pointer-events-auto overflow-y-scroll max-h-[84vh]"
>
<div class="text-2xl font-semibold flex items-center bg-neutral-900 w-full my-2">
<DocumentArrowUpIcon class="w-7 h-7 mr-3" /> Export Regions

<button
class="w-8 h-8 ml-auto rounded hover:bg-slate-800 text-slate-300 shrink-0 flex items-center justify-center"
@click="emit('close')"
>
<XMarkIcon class="w-4 h-4" />
</button>
</div>

<div class="mt-8">
<div class="font-bold uppercase text-sm">
Output Format
</div>

<div class="text-gray-300 text-sm mt-1">
Plain format will export binary,
while HexV3 is designed for use with Logism Evolution.
</div>

<select
id="data-type"
class="appearance-none uppercase font-bold text-sm bg-neutral-800 text-neutral-300 px-4 py-2 my-2 w-48 rounded"
:value="state.kind"
@input="event => state.kind = event.target.value"

Check failure on line 31 in src/components/ExportOverlay.vue

View workflow job for this annotation

GitHub Actions / Build Target (macos-latest)

'event.target' is possibly 'null'.

Check failure on line 31 in src/components/ExportOverlay.vue

View workflow job for this annotation

GitHub Actions / Build Target (macos-latest)

Property 'value' does not exist on type 'EventTarget'.

Check failure on line 31 in src/components/ExportOverlay.vue

View workflow job for this annotation

GitHub Actions / Build Target (ubuntu-20.04)

'event.target' is possibly 'null'.

Check failure on line 31 in src/components/ExportOverlay.vue

View workflow job for this annotation

GitHub Actions / Build Target (ubuntu-20.04)

Property 'value' does not exist on type 'EventTarget'.

Check failure on line 31 in src/components/ExportOverlay.vue

View workflow job for this annotation

GitHub Actions / Build Target (windows-latest)

'event.target' is possibly 'null'.

Check failure on line 31 in src/components/ExportOverlay.vue

View workflow job for this annotation

GitHub Actions / Build Target (windows-latest)

Property 'value' does not exist on type 'EventTarget'.
>
<option value="plain">Plain</option>
<option value="hex_v3">HexV3</option>
</select>
</div>

<div class="mt-8">
<div class="font-bold uppercase text-sm">
Continuous Export
</div>

<div class="text-gray-300 text-sm mt-1">
A continuous export will create one large file with all regions back to back.
</div>

<ToggleField
class="my-2"
title="Continuous Export"
v-model="state.continuous"
/>
</div>

<div class="flex items-center mt-4">
<div class="text-sm text-gray-400">
Continuous exports may result in large file exports (> 800MB).
</div>

<button
class="rounded px-6 py-3 bg-gray-800 hover:bg-gray-700 transition-colors uppercase font-bold text-sm ml-auto active:bg-slate-700"
@click="exportRegions()"
>
Export
</button>
</div>
</div>
</Modal>
</template>

<script setup lang="ts">
import Modal from './Modal.vue'
import { tab } from '../state/state'
import { consoleData, ConsoleType, DebugTab, openConsole, pushConsole } from '../state/console-data'
import { assembleRegions, assembleRegionsContinuous, AssembleRegionsOptions } from '../utils/mips'
import { collectLines } from '../utils/tabs'
import { SelectedFile, selectSaveDestination } from '../utils/query/select-file'
import { writeHexRegions } from '../utils/query/serialize-files'
import { postBuildMessage } from '../utils/debug'
import { DocumentArrowUpIcon, XMarkIcon } from '@heroicons/vue/24/solid'
import { reactive } from 'vue'
import ToggleField from './console/ToggleField.vue'
import { writeFile } from '@tauri-apps/api/fs'
const state = reactive({
continuous: true,
kind: 'hex_v3'
} as AssembleRegionsOptions)
const props = defineProps<{
show: boolean
}>()
const emit = defineEmits(['close'])
async function exportRegions() {
emit('close')
const current = tab()
if (!current) {
return
}
if (current.profile && current.profile.kind !== 'asm') {
consoleData.showConsole = true
openConsole()
pushConsole('Generating hex regions directly from an elf file is not supported.', ConsoleType.Info)
pushConsole('Use an un-assembled assembly file, or submit ' +
'a feature request at https://github.com/1whatleytay/saturn.', ConsoleType.Info)
return
}
if (state.continuous) {
const result = await assembleRegionsContinuous(collectLines(current.lines), current.path, state)
let destination: SelectedFile<undefined> | null = null
if (result.data !== null) {
destination = await selectSaveDestination('Save Region File')
if (!destination) {
return
}
await writeFile(destination.path, result.data)
}
consoleData.showConsole = true
postBuildMessage(result.result)
if (destination !== null) {
consoleData.tab = DebugTab.Console
pushConsole(`Continuous hex regions written to ${destination.path}`, ConsoleType.Info)
}
} else {
const result = await assembleRegions(collectLines(current.lines), current.path, state)
let destination: SelectedFile<undefined> | null = null
if (result.regions !== null) {
destination = await selectSaveDestination('Save Directory')
if (!destination) {
return
}
await writeHexRegions(destination.path, result.regions)
}
consoleData.showConsole = true
postBuildMessage(result.result)
if (destination !== null) {
consoleData.tab = DebugTab.Console
pushConsole(`Hex regions written to ${destination.path}`, ConsoleType.Info)
}
}
}
</script>
2 changes: 1 addition & 1 deletion src/components/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@click="emit('close')"
/>

<div v-if="show" class="fixed absolute z-50 top-12 w-full pointer-events-none">
<div v-if="show" class="absolute z-50 top-12 w-full pointer-events-none">
<span class="pointer-events-auto">
<slot />
</span>
Expand Down
Loading

0 comments on commit 16bbb3a

Please sign in to comment.