Revamp desktop usability and multiline fields
This commit is contained in:
@@ -172,7 +172,6 @@ impl EntryFieldDraft {
|
||||
pub fn field(name: impl Into<String>, value: Vec<u8>) -> Result<Self, DocumentError> {
|
||||
let name = name.into();
|
||||
validate_name(&name)?;
|
||||
validate_line(&value)?;
|
||||
let value = SecretBytes::new(value);
|
||||
let mut contents = Vec::with_capacity(name.len() + value.expose().len() + 2);
|
||||
contents.extend_from_slice(name.as_bytes());
|
||||
@@ -197,6 +196,12 @@ impl EntryFieldDraft {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multiline(contents: Vec<u8>) -> Self {
|
||||
Self {
|
||||
contents: SecretBytes::new(contents),
|
||||
}
|
||||
}
|
||||
|
||||
fn render(self) -> SecretBytes {
|
||||
self.contents
|
||||
}
|
||||
@@ -283,9 +288,8 @@ impl EntryDocument {
|
||||
let field = self.field(id).ok_or(DocumentError::UnknownField { id })?;
|
||||
let draft = match field.metadata().kind() {
|
||||
EntryFieldKind::OtpUri => EntryFieldDraft::otp_uri(value)?,
|
||||
EntryFieldKind::Password | EntryFieldKind::Note | EntryFieldKind::Blank => {
|
||||
EntryFieldDraft::line(value)?
|
||||
}
|
||||
EntryFieldKind::Password => EntryFieldDraft::line(value)?,
|
||||
EntryFieldKind::Note | EntryFieldKind::Blank => EntryFieldDraft::multiline(value),
|
||||
EntryFieldKind::Username
|
||||
| EntryFieldKind::Email
|
||||
| EntryFieldKind::Url
|
||||
@@ -540,7 +544,32 @@ fn parse_lines(contents: &[u8]) -> Vec<EntryField> {
|
||||
});
|
||||
start = end;
|
||||
}
|
||||
fields
|
||||
let mut logical = Vec::<EntryField>::new();
|
||||
for field in fields {
|
||||
let continuation = classify(logical.len(), field.contents.expose()).kind
|
||||
== EntryFieldKind::Note
|
||||
&& logical.last().is_some_and(|previous| {
|
||||
let metadata =
|
||||
classify(logical.len().saturating_sub(1), previous.contents.expose());
|
||||
metadata.name.is_some() && metadata.kind != EntryFieldKind::OtpUri
|
||||
});
|
||||
if continuation {
|
||||
let previous = logical
|
||||
.last_mut()
|
||||
.expect("continuation has a previous field");
|
||||
let mut contents = previous.contents.expose().to_vec();
|
||||
contents.extend_from_slice(&previous.ending);
|
||||
contents.extend_from_slice(field.contents.expose());
|
||||
previous.contents = SecretBytes::new(contents);
|
||||
previous.ending = field.ending;
|
||||
} else {
|
||||
logical.push(field);
|
||||
}
|
||||
}
|
||||
for (id, field) in logical.iter_mut().enumerate() {
|
||||
field.id = EntryFieldId(id as u64);
|
||||
}
|
||||
logical
|
||||
}
|
||||
|
||||
fn classify_all(fields: &mut [EntryField]) {
|
||||
@@ -595,8 +624,13 @@ fn classify(index: usize, line: &[u8]) -> EntryFieldMetadata {
|
||||
value: 0..line.len(),
|
||||
};
|
||||
}
|
||||
if let Some(colon) = line.iter().position(|byte| *byte == b':') {
|
||||
let raw_name = trim_ascii(&line[..colon]);
|
||||
let first_line_end = line
|
||||
.iter()
|
||||
.position(|byte| *byte == b'\n')
|
||||
.unwrap_or(line.len());
|
||||
let first_line = &line[..first_line_end];
|
||||
if let Some(colon) = first_line.iter().position(|byte| *byte == b':') {
|
||||
let raw_name = trim_ascii(&first_line[..colon]);
|
||||
if !raw_name.is_empty()
|
||||
&& let Ok(name) = std::str::from_utf8(raw_name)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user