You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by ar...@apache.org on 2023/08/21 21:08:30 UTC

[daffodil-vscode] branch main updated: Fixed Multiple Data Editor Editing / Display Items

This is an automated email from the ASF dual-hosted git repository.

arosien pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil-vscode.git


The following commit(s) were added to refs/heads/main by this push:
     new af689c7  Fixed Multiple Data Editor Editing / Display Items
af689c7 is described below

commit af689c7b55cc1b1223257134f82535e0232f62d4
Author: Robert Strickland <st...@gmail.com>
AuthorDate: Mon Aug 21 10:27:58 2023 -0500

    Fixed Multiple Data Editor Editing / Display Items
    
    - Fixed issue where binary display radix would still display 16 bytes
      per row, instead of 8.
    - Fixed inability to edit a "non-regular" sized file ( file size < 2 )
    - Rerouted all file / viewport UI offset traversal to use toplevel
      `seek()` function.
    
    Closes #821
    Closes #783
---
 .../DataDisplays/CustomByteDisplay/BinaryData.ts   |  38 +++++-
 .../CustomByteDisplay/DataLineFeed.svelte          | 114 +++++++++--------
 .../CustomByteDisplay/DataValue.svelte             |  10 +-
 .../FileTraversalIndicator.svelte                  |   5 +-
 .../components/DataDisplays/DataViewports.svelte   |   3 -
 .../src/components/Editors/DataEditor.svelte       |  13 +-
 .../Header/fieldsets/SearchReplace.svelte          |   2 +
 .../components/Header/fieldsets/Settings.svelte    |   3 +
 src/svelte/src/components/dataEditor.svelte        | 142 +++++++++++----------
 src/svelte/src/stores/index.ts                     |  55 ++++++--
 src/svelte/src/utilities/display.ts                |  16 ++-
 src/svelte/src/utilities/elementKeypressEvents.ts  |   1 -
 src/svelte/src/utilities/highlights.ts             |   2 +
 13 files changed, 250 insertions(+), 154 deletions(-)

diff --git a/src/svelte/src/components/DataDisplays/CustomByteDisplay/BinaryData.ts b/src/svelte/src/components/DataDisplays/CustomByteDisplay/BinaryData.ts
index dec18d0..95e75e4 100644
--- a/src/svelte/src/components/DataDisplays/CustomByteDisplay/BinaryData.ts
+++ b/src/svelte/src/components/DataDisplays/CustomByteDisplay/BinaryData.ts
@@ -16,8 +16,16 @@
  */
 
 import { SimpleWritable } from '../../../stores/localStore'
-import type { RadixValues } from '../../../stores/configuration'
-import { radixBytePad } from '../../../utilities/display'
+import {
+  NUM_LINES_DISPLAYED,
+  type BytesPerRow,
+  type RadixValues,
+  VIEWPORT_CAPACITY_MAX,
+} from '../../../stores/configuration'
+import {
+  radixBytePad,
+  viewport_offset_to_line_num,
+} from '../../../utilities/display'
 
 export const BYTE_ACTION_DIV_OFFSET: number = 24
 
@@ -97,6 +105,32 @@ export class ViewportDataStore_t extends SimpleWritable<ViewportData_t> {
     this._offsetMax = value.fileOffset + value.bytesLeft + value.length
   }
 
+  public lowerFetchBoundary(): number {
+    return this.storeData().fileOffset
+  }
+
+  public upperFetchBoundary(bytesPerRow: BytesPerRow): number {
+    const store = this.storeData()
+    const boundary =
+      store.fileOffset + store.length - NUM_LINES_DISPLAYED * bytesPerRow
+
+    return boundary
+  }
+
+  public lineTopMax(bytesPerRow: BytesPerRow): number {
+    const vpMaxOffset = Math.max(
+      0,
+      this.storeData().length - NUM_LINES_DISPLAYED * bytesPerRow
+    )
+    const vpLineTopMax = viewport_offset_to_line_num(
+      vpMaxOffset + this.storeData().fileOffset,
+      this.storeData().fileOffset,
+      bytesPerRow
+    )
+
+    return vpLineTopMax + 1
+  }
+
   public physical_byte_values(
     radix: RadixValues,
     bytesPerRow: 16 | 8
diff --git a/src/svelte/src/components/DataDisplays/CustomByteDisplay/DataLineFeed.svelte b/src/svelte/src/components/DataDisplays/CustomByteDisplay/DataLineFeed.svelte
index 7051354..7d4d08d 100644
--- a/src/svelte/src/components/DataDisplays/CustomByteDisplay/DataLineFeed.svelte
+++ b/src/svelte/src/components/DataDisplays/CustomByteDisplay/DataLineFeed.svelte
@@ -28,11 +28,11 @@ limitations under the License.
     searchQuery,
     editorActionsAllowed,
     dataFeedLineTop,
+    seekOffsetInput,
   } from '../../../stores'
   import {
     EditByteModes,
     NUM_LINES_DISPLAYED,
-    type BytesPerRow,
     type RadixValues,
     EditActionRestrictions,
     VIEWPORT_SCROLL_INCREMENT,
@@ -52,6 +52,7 @@ limitations under the License.
   import FileTraversalIndicator from './FileTraversalIndicator.svelte'
   import {
     byteDivWidthFromRadix,
+    line_num_to_file_offset,
     viewport_offset_to_line_num,
   } from '../../../utilities/display'
   import SelectedByteEdit from './SelectedByteEdit.svelte'
@@ -63,11 +64,10 @@ limitations under the License.
     selectionHighlights,
     searchResultsHighlights,
     updateSearchResultsHighlights,
+    searchResultsUpdated,
   } from '../../../utilities/highlights'
-
-  // export let $dataFeedLineTop: number
+  import { bytesPerRow } from '../../../stores'
   export let awaitViewportSeek: boolean
-  export let bytesPerRow: BytesPerRow = 16
   export let dataRadix: RadixValues = 16
   export let addressRadix: RadixValues = 16
   export let viewportData: ViewportData_t
@@ -81,7 +81,7 @@ limitations under the License.
     numLinesToScroll: number
   ) {
     const newLineTopOffset =
-      numLinesToScroll * bytesPerRow + $dataFeedLineTop * bytesPerRow
+      numLinesToScroll * $bytesPerRow + $dataFeedLineTop * $bytesPerRow
     let scroll_count = Math.floor(newLineTopOffset / VIEWPORT_SCROLL_INCREMENT)
 
     if (direction === ViewportScrollDirection.INCREMENT) {
@@ -89,8 +89,8 @@ limitations under the License.
         viewportData.fileOffset + scroll_count * VIEWPORT_SCROLL_INCREMENT
       if (fetchBound > $fileMetrics.computedSize)
         return (
-          ($fileMetrics.computedSize / bytesPerRow) * bytesPerRow -
-          NUM_LINES_DISPLAYED * bytesPerRow
+          ($fileMetrics.computedSize / $bytesPerRow) * $bytesPerRow -
+          NUM_LINES_DISPLAYED * $bytesPerRow
         )
 
       return fetchBound
@@ -107,22 +107,44 @@ limitations under the License.
   }
 
   const INCREMENT_LINE = () => {
-    handle_navigation(1)
+    $seekOffsetInput = line_num_to_file_offset(
+      $dataFeedLineTop + 1,
+      viewportData.fileOffset,
+      $bytesPerRow
+    ).toString(addressRadix)
+    eventDispatcher('seek')
   }
   const DECREMENT_LINE = () => {
-    handle_navigation(-1)
+    $seekOffsetInput = line_num_to_file_offset(
+      $dataFeedLineTop - 1,
+      viewportData.fileOffset,
+      $bytesPerRow
+    ).toString(addressRadix)
+    eventDispatcher('seek')
   }
   const INCREMENT_SEGMENT = () => {
-    handle_navigation(NUM_LINES_DISPLAYED)
+    $seekOffsetInput = line_num_to_file_offset(
+      $dataFeedLineTop + NUM_LINES_DISPLAYED,
+      viewportData.fileOffset,
+      $bytesPerRow
+    ).toString(addressRadix)
+    eventDispatcher('seek')
   }
   const DECREMENT_SEGMENT = () => {
-    handle_navigation(-NUM_LINES_DISPLAYED)
+    $seekOffsetInput = line_num_to_file_offset(
+      $dataFeedLineTop - NUM_LINES_DISPLAYED,
+      viewportData.fileOffset,
+      $bytesPerRow
+    ).toString(addressRadix)
+    eventDispatcher('seek')
   }
   const SCROLL_TO_END = () => {
-    handle_navigation(lineTopMaxFile)
+    $seekOffsetInput = $fileMetrics.computedSize.toString(addressRadix)
+    eventDispatcher('seek')
   }
   const SCROLL_TO_TOP = () => {
-    handle_navigation(-lineTopMaxFile)
+    $seekOffsetInput = '0'
+    eventDispatcher('seek')
   }
 
   let totalLinesPerFilesize = 0
@@ -171,8 +193,8 @@ limitations under the License.
 
   $: themeClass = $UIThemeCSSClass
   $: {
-    totalLinesPerFilesize = Math.ceil($fileMetrics.computedSize / bytesPerRow)
-    totalLinesPerViewport = Math.ceil(viewportData.data.length / bytesPerRow)
+    totalLinesPerFilesize = Math.ceil($fileMetrics.computedSize / $bytesPerRow)
+    totalLinesPerViewport = Math.ceil(viewportData.data.length / $bytesPerRow)
     lineTopMaxFile = Math.max(totalLinesPerFilesize - NUM_LINES_DISPLAYED, 0)
     lineTopMaxViewport = Math.max(
       totalLinesPerViewport - NUM_LINES_DISPLAYED,
@@ -188,56 +210,54 @@ limitations under the License.
       $selectionDataStore.active || (atViewportHead && atFileHead)
     disableIncrement =
       $selectionDataStore.active || (atViewportTail && atFileTail)
-    lineTopFileOffset = $dataFeedLineTop * bytesPerRow
+    lineTopFileOffset = $dataFeedLineTop * $bytesPerRow
   }
 
   $: {
+    activeSelection = $selectionHighlights
+    searchResults = $searchResultsHighlights
     if (
-      viewportData.fileOffset >= 0 &&
-      !awaitViewportSeek &&
-      $dataFeedLineTop >= 0
+      (viewportData.fileOffset >= 0 &&
+        !awaitViewportSeek &&
+        $dataFeedLineTop >= 0) ||
+      $searchResultsUpdated
     ) {
       if (
         viewportLines.length !== 0 &&
-        bytesPerRow !== viewportLines[0].bytes.length
+        $bytesPerRow !== viewportLines[0].bytes.length
       ) {
         $dataFeedLineTop = viewport_offset_to_line_num(
           parseInt(viewportLines[0].offset, addressRadix),
           viewportData.fileOffset,
-          bytesPerRow
+          $bytesPerRow
         )
       }
 
       viewportLines = generate_line_data(
         $dataFeedLineTop,
         dataRadix,
-        addressRadix,
-        bytesPerRow
+        addressRadix
       )
+      $searchResultsUpdated = false
     }
   }
   $: byteElementWidth = byteDivWidthFromRadix(dataRadix)
-  $: {
-    activeSelection = $selectionHighlights
-    searchResults = $searchResultsHighlights
-  }
 
   function generate_line_data(
     startIndex: number,
     dataRadix: RadixValues,
     addressRadix: RadixValues,
-    bytesPerRow: BytesPerRow,
     endIndex: number = startIndex + (NUM_LINES_DISPLAYED - 1)
   ): Array<ViewportLineData> {
     let ret = []
     for (let i = startIndex; i <= endIndex; i++) {
-      const viewportLineOffset = i * bytesPerRow
+      const viewportLineOffset = i * $bytesPerRow
       const fileOffset = viewportLineOffset + viewportData.fileOffset
 
       let bytes: Array<ByteValue> = []
       const highlight = i % 2 === 0
 
-      for (let bytePos = 0; bytePos < bytesPerRow; bytePos++) {
+      for (let bytePos = 0; bytePos < $bytesPerRow; bytePos++) {
         let byteOffset = viewportLineOffset + bytePos
         bytes.push({
           offset: byteOffset,
@@ -251,7 +271,7 @@ limitations under the License.
 
       ret.push({
         offset: fileOffset.toString(addressRadix).padStart(8, '0'),
-        fileLine: fileOffset / bytesPerRow,
+        fileLine: fileOffset / $bytesPerRow,
         bytes: bytes,
         highlight: highlight ? 'even' : 'odd',
       })
@@ -311,7 +331,7 @@ limitations under the License.
         nextViewportOffset: nextViewportOffset,
         lineTopOnRefresh:
           Math.floor(
-            (viewportOffset + lineTopOffset - nextViewportOffset) / bytesPerRow
+            (viewportOffset + lineTopOffset - nextViewportOffset) / $bytesPerRow
           ) + numLinesToScroll,
       })
       return
@@ -413,9 +433,9 @@ limitations under the License.
     const offset =
       Math.ceil(
         ($fileMetrics.computedSize * (percentageTraversed / 100.0)) /
-          bytesPerRow
-      ) * bytesPerRow
-    const firstPageThreshold = bytesPerRow * NUM_LINES_DISPLAYED
+          $bytesPerRow
+      ) * $bytesPerRow
+    const firstPageThreshold = $bytesPerRow * NUM_LINES_DISPLAYED
     const lastPageThreshold = $fileMetrics.computedSize - firstPageThreshold
     if (offset <= firstPageThreshold) {
       // scroll to the top because we are somewhere in the first page
@@ -425,13 +445,8 @@ limitations under the License.
       SCROLL_TO_END()
     } else {
       // scroll to the offset since we are not in the first or last page
-      vscode.postMessage({
-        command: MessageCommand.scrollViewport,
-        data: {
-          scrollOffset: offset,
-          bytesPerRow: bytesPerRow,
-        },
-      })
+      $seekOffsetInput = offset.toString(addressRadix)
+      eventDispatcher('seek')
       lineTopOnRefresh = lineTopMaxViewport
       awaitViewportSeek = true
     }
@@ -495,7 +510,6 @@ limitations under the License.
       <div class="address" id="address">
         <b>{viewportLine.offset}</b>
       </div>
-
       <div
         class="byte-line"
         id="physical-line-{i.toString(16).padStart(2, '0')}"
@@ -510,14 +524,13 @@ limitations under the License.
             id={'physical'}
             radix={dataRadix}
             width={byteElementWidth}
-            disabled={byte.offset > viewportData.length}
+            disabled={!byte.value}
             bind:selectionData={$selectionDataStore}
             on:mouseup={mouseup}
             on:mousedown={mousedown}
           />
         {/each}
       </div>
-
       <div
         class="byte-line"
         id="logical-line-{i.toString(16).padStart(2, '0')}"
@@ -532,7 +545,7 @@ limitations under the License.
             id={'logical'}
             radix={dataRadix}
             width={byteElementWidth}
-            disabled={byte.offset > viewportData.length}
+            disabled={!byte.value}
             bind:selectionData={$selectionDataStore}
             on:mouseup={mouseup}
             on:mousedown={mousedown}
@@ -551,7 +564,6 @@ limitations under the License.
       maxDisplayLines={NUM_LINES_DISPLAYED}
       bind:percentageTraversed
       on:indicatorClicked={handleClickedIndicator}
-      {bytesPerRow}
     />
     <FlexContainer --dir="row">
       <Button
@@ -570,7 +582,7 @@ limitations under the License.
         disabledBy={disableIncrement}
         width="30pt"
         description="Increment offset by {NUM_LINES_DISPLAYED *
-          bytesPerRow} bytes"
+          $bytesPerRow} bytes"
         tooltipAlwaysEnabled={true}
       >
         <span slot="left" class="btn-icon material-symbols-outlined"
@@ -581,7 +593,7 @@ limitations under the License.
         fn={INCREMENT_LINE}
         disabledBy={disableIncrement}
         width="30pt"
-        description="Increment offset by {bytesPerRow} bytes"
+        description="Increment offset by {$bytesPerRow} bytes"
         tooltipAlwaysEnabled={true}
       >
         <span slot="left" class="btn-icon material-symbols-outlined"
@@ -592,7 +604,7 @@ limitations under the License.
         fn={DECREMENT_LINE}
         disabledBy={disableDecrement}
         width="30pt"
-        description="Decrement offset by {bytesPerRow} bytes"
+        description="Decrement offset by {$bytesPerRow} bytes"
         tooltipAlwaysEnabled={true}
       >
         <span slot="left" class="btn-icon material-symbols-outlined"
@@ -604,7 +616,7 @@ limitations under the License.
         disabledBy={disableDecrement}
         width="30pt"
         description="Decrement offset by {NUM_LINES_DISPLAYED *
-          bytesPerRow} bytes"
+          $bytesPerRow} bytes"
         tooltipAlwaysEnabled={true}
       >
         <span slot="left" class="btn-icon material-symbols-outlined"
diff --git a/src/svelte/src/components/DataDisplays/CustomByteDisplay/DataValue.svelte b/src/svelte/src/components/DataDisplays/CustomByteDisplay/DataValue.svelte
index fdcc1c8..ab12df4 100644
--- a/src/svelte/src/components/DataDisplays/CustomByteDisplay/DataValue.svelte
+++ b/src/svelte/src/components/DataDisplays/CustomByteDisplay/DataValue.svelte
@@ -39,7 +39,6 @@ limitations under the License.
 
   const eventDispatcher = createEventDispatcher()
 
-  let consideredForSelection = false
   let makingSelection = false
 
   $: {
@@ -50,6 +49,11 @@ limitations under the License.
 
   function mouse_enter_handle(event: MouseEvent) {
     if (!makingSelection) return
+    if (disabled) {
+      selectionData.endOffset = -1
+      makingSelection = false
+      return
+    }
     selectionData.endOffset = byte.offset
   }
   function mouse_leave_handle(event: MouseEvent) {
@@ -78,7 +82,6 @@ limitations under the License.
     class:isSelected
     class:isSearchResult
     class:possibleSelection
-    class:selecting={consideredForSelection}
     id={id + '-' + byte.offset.toString()}
     style:width
     on:mouseup={mouse_event_handle}
@@ -95,12 +98,13 @@ limitations under the License.
     class:isSelected
     class:isSearchResult
     class:possibleSelection
-    class:selecting={consideredForSelection}
     id={id + '-' + byte.offset.toString()}
     style:width={'20px'}
     class:latin1Undefined={latin1Undefined(byte.value)}
     on:mouseup={mouse_event_handle}
     on:mousedown={mouse_event_handle}
+    on:mouseenter={mouse_enter_handle}
+    on:mouseleave={mouse_leave_handle}
   >
     {latin1Undefined(byte.value) ? '' : String.fromCharCode(byte.value)}
   </div>
diff --git a/src/svelte/src/components/DataDisplays/CustomByteDisplay/FileTraversalIndicator.svelte b/src/svelte/src/components/DataDisplays/CustomByteDisplay/FileTraversalIndicator.svelte
index 7c7b8f4..96496be 100644
--- a/src/svelte/src/components/DataDisplays/CustomByteDisplay/FileTraversalIndicator.svelte
+++ b/src/svelte/src/components/DataDisplays/CustomByteDisplay/FileTraversalIndicator.svelte
@@ -16,13 +16,12 @@ limitations under the License.
 -->
 <script lang="ts">
   import { createEventDispatcher } from 'svelte'
-
+  import { bytesPerRow } from '../../../stores'
   const eventDispatcher = createEventDispatcher()
 
   export let totalLines = 0
   export let currentLine = 0
   export let fileOffset = 0
-  export let bytesPerRow = 16
   export let percentageTraversed
   export let maxDisplayLines = 20
   export let selectionActive: boolean
@@ -42,7 +41,7 @@ limitations under the License.
     } else {
       indicatorClickDisabled = false
       percentageTraversed =
-        ((currentLine + (fileOffset / bytesPerRow + 20)) / totalLines) * 100.0
+        ((currentLine + (fileOffset / $bytesPerRow + 20)) / totalLines) * 100.0
       if (indicatorContainer)
         indicatorContainer.addEventListener('click', updatePercentageTraversed)
     }
diff --git a/src/svelte/src/components/DataDisplays/DataViewports.svelte b/src/svelte/src/components/DataDisplays/DataViewports.svelte
index 2c0cafe..99f4d25 100644
--- a/src/svelte/src/components/DataDisplays/DataViewports.svelte
+++ b/src/svelte/src/components/DataDisplays/DataViewports.svelte
@@ -17,9 +17,7 @@ limitations under the License.
 <script lang="ts">
   import {
     addressRadix,
-    bytesPerRow,
     displayRadix,
-    dataFeedLineTop,
     dataFeedAwaitRefresh,
     viewport,
   } from '../../stores'
@@ -32,7 +30,6 @@ limitations under the License.
   on:applyChanges
   on:handleEditorEvent
   viewportData={$viewport}
-  bytesPerRow={$bytesPerRow}
   dataRadix={$displayRadix}
   addressRadix={$addressRadix}
   bind:awaitViewportSeek={$dataFeedAwaitRefresh}
diff --git a/src/svelte/src/components/Editors/DataEditor.svelte b/src/svelte/src/components/Editors/DataEditor.svelte
index d1d0987..f8d51b1 100644
--- a/src/svelte/src/components/Editors/DataEditor.svelte
+++ b/src/svelte/src/components/Editors/DataEditor.svelte
@@ -15,7 +15,12 @@ See the License for the specific language governing permissions and
 limitations under the License.
 -->
 <script lang="ts">
-  import { editorSelection, editMode, selectionDataStore } from '../../stores'
+  import {
+    editorSelection,
+    editMode,
+    selectionDataStore,
+    regularSizedFile,
+  } from '../../stores'
   import { EditByteModes } from '../../stores/configuration'
   import { UIThemeCSSClass } from '../../utilities/colorScheme'
   import { createEventDispatcher } from 'svelte'
@@ -30,7 +35,9 @@ limitations under the License.
         {
           const eventDetails = event as InputEvent
           const editorElement = eventDetails.target as HTMLTextAreaElement
-          $editorSelection = editorElement.value
+          editorSelection.update(() => {
+            return editorElement.value
+          })
         }
 
         break
@@ -45,7 +52,7 @@ limitations under the License.
 </script>
 
 <div class="editView" id="edit_view">
-  {#if $editMode === EditByteModes.Multiple && $selectionDataStore.active}
+  {#if $editMode === EditByteModes.Multiple && ($selectionDataStore.active || !$regularSizedFile)}
     <textarea
       class={$UIThemeCSSClass}
       id="selectedContent"
diff --git a/src/svelte/src/components/Header/fieldsets/SearchReplace.svelte b/src/svelte/src/components/Header/fieldsets/SearchReplace.svelte
index 7f32d7a..0ba4114 100644
--- a/src/svelte/src/components/Header/fieldsets/SearchReplace.svelte
+++ b/src/svelte/src/components/Header/fieldsets/SearchReplace.svelte
@@ -29,6 +29,7 @@ limitations under the License.
     searchErr,
     searchQuery,
     seekErr,
+    dataFeedAwaitRefresh,
   } from '../../../stores'
   import { vscode } from '../../../utilities/vscode'
   import { MessageCommand } from '../../../utilities/message'
@@ -255,6 +256,7 @@ limitations under the License.
         searchStarted = replaceStarted = false
         if (msg.data.data.replacementsCount > 0) {
           // subtract 1 from the next offset because search next will add 1
+          clearSearchResultsHighlights()
           matchOffset = msg.data.data.nextOffset - 1
           preReplaceHasPrev = hasPrev
           justReplaced = true
diff --git a/src/svelte/src/components/Header/fieldsets/Settings.svelte b/src/svelte/src/components/Header/fieldsets/Settings.svelte
index 2605a7e..5a0c841 100644
--- a/src/svelte/src/components/Header/fieldsets/Settings.svelte
+++ b/src/svelte/src/components/Header/fieldsets/Settings.svelte
@@ -24,9 +24,12 @@ limitations under the License.
     displayRadix,
     editorEncoding,
     editorActionsAllowed,
+    bytesPerRow,
   } from '../../../stores'
   import FlexContainer from '../../layouts/FlexContainer.svelte'
   import { UIThemeCSSClass } from '../../../utilities/colorScheme'
+
+  $: $bytesPerRow = $displayRadix === RADIX_OPTIONS.Binary ? 8 : 16
 </script>
 
 <fieldset>
diff --git a/src/svelte/src/components/dataEditor.svelte b/src/svelte/src/components/dataEditor.svelte
index a64acfe..5ed6520 100644
--- a/src/svelte/src/components/dataEditor.svelte
+++ b/src/svelte/src/components/dataEditor.svelte
@@ -33,9 +33,9 @@ limitations under the License.
     dataFeedLineTop,
     SelectionData_t,
     dataFeedAwaitRefresh,
-    fileMetrics,
     viewport,
     searchQuery,
+    regularSizedFile,
   } from '../stores'
   import {
     CSSThemeClass,
@@ -48,9 +48,8 @@ limitations under the License.
   import Main from './Main.svelte'
   import {
     EditByteModes,
-    NUM_LINES_DISPLAYED,
-    VIEWPORT_CAPACITY_MAX,
     VIEWPORT_SCROLL_INCREMENT,
+    type BytesPerRow,
   } from '../stores/configuration'
   import ServerMetrics from './ServerMetrics/ServerMetrics.svelte'
   import {
@@ -61,10 +60,7 @@ limitations under the License.
     EditEvent,
     ViewportData_t,
   } from './DataDisplays/CustomByteDisplay/BinaryData'
-  import {
-    byte_count_divisible_offset,
-    viewport_offset_to_line_num,
-  } from '../utilities/display'
+  import { byte_count_divisible_offset } from '../utilities/display'
   import { clearSearchResultsHighlights } from '../utilities/highlights'
 
   $: $UIThemeCSSClass = $darkUITheme ? CSSThemeClass.Dark : CSSThemeClass.Light
@@ -86,71 +82,72 @@ limitations under the License.
     }
   }
 
+  function offset_to_viewport_line_number(
+    offset: number,
+    bytesPerRow: BytesPerRow,
+    viewportStartOffset: number = $viewport.fileOffset
+  ): number {
+    const nearestBPRdivisibleOffset = byte_count_divisible_offset(
+      offset - viewportStartOffset,
+      bytesPerRow
+    )
+    const offsetLineNumInViewport = nearestBPRdivisibleOffset / bytesPerRow
+    return offsetLineNumInViewport
+  }
+
+  function fetchable_content(offset: number): boolean {
+    return offset > $viewport.fileOffset
+      ? $viewport.bytesLeft > 0
+      : $viewport.fileOffset > 0
+  }
+
+  function should_fetch_new_viewoprt(offset: number) {
+    const lowerBound = viewport.lowerFetchBoundary()
+    const upperBound = viewport.upperFetchBoundary($bytesPerRow)
+    const fetchableContent = fetchable_content(offset)
+    if (!fetchableContent) return false
+
+    const boundaryTripped = offset < lowerBound || offset > upperBound
+
+    return boundaryTripped
+  }
+
+  function target_offset_in_viewport(offset: number): boolean {
+    return offset >= $viewport.fileOffset && offset <= $viewport.length
+  }
+
   function seek(offsetArg?: number) {
     if (!offsetArg) offsetArg = $seekOffset
 
-    const fileSize = $fileMetrics.computedSize
-    const viewportBoundary =
-      $viewport.length +
-      $viewport.fileOffset -
-      NUM_LINES_DISPLAYED * $bytesPerRow
-    const offset =
-      offsetArg > 0 &&
-      offsetArg < viewport.offsetMax &&
-      offsetArg % $bytesPerRow === 0
-        ? offsetArg + 1
-        : offsetArg
-
-    const relativeFileLine = Math.floor(offset / $bytesPerRow)
-    const relativeFileOffset = relativeFileLine * $bytesPerRow
-    const lineTopBoundary =
-      Math.floor($viewport.length / $bytesPerRow) - NUM_LINES_DISPLAYED
-    let relativeTargetLine = relativeFileLine
-    let viewportStartOffset = $viewport.fileOffset
-    $dataFeedAwaitRefresh = true
-    // make sure that the offset is within the loaded viewport
-    if (
-      offset < $viewport.fileOffset ||
-      offset > viewportBoundary ||
-      relativeTargetLine > lineTopBoundary
-    ) {
-      let adjustedFileOffset = Math.max(
-        0,
-        relativeFileOffset - VIEWPORT_SCROLL_INCREMENT
+    const shouldFetchData = should_fetch_new_viewoprt(offsetArg)
+
+    if (!shouldFetchData) {
+      $dataFeedLineTop = Math.min(
+        viewport.lineTopMax($bytesPerRow),
+        offset_to_viewport_line_number(offsetArg, $bytesPerRow)
       )
-      const fetchPastFileBoundary =
-        fileSize - adjustedFileOffset < VIEWPORT_CAPACITY_MAX
-      if (fetchPastFileBoundary)
-        adjustedFileOffset = byte_count_divisible_offset(
-          fileSize - VIEWPORT_CAPACITY_MAX,
-          $bytesPerRow,
-          1
-        )
-
-      viewportStartOffset = adjustedFileOffset
-      relativeTargetLine = fetchPastFileBoundary
-        ? viewport_offset_to_line_num(
-            offset,
-            viewportStartOffset,
-            $bytesPerRow
-          ) -
-          (NUM_LINES_DISPLAYED - 1)
-        : viewport_offset_to_line_num(offset, viewportStartOffset, $bytesPerRow)
-
-      // NOTE: Scrolling the viewport will make the display bounce until it goes to the correct offset
-      vscode.postMessage({
-        command: MessageCommand.scrollViewport,
-        data: {
-          // scroll the viewport with the offset in the middle
-          scrollOffset: viewportStartOffset,
-          bytesPerRow: $bytesPerRow,
-          numLinesDisplayed: $viewportNumLinesDisplayed,
-        },
-      })
+      return
     }
 
-    $dataFeedLineTop = relativeTargetLine
-    $dataFeedAwaitRefresh = false
+    $dataFeedAwaitRefresh = true
+
+    offsetArg = byte_count_divisible_offset(offsetArg, $bytesPerRow)
+    const fetchOffset = Math.max(0, offsetArg - VIEWPORT_SCROLL_INCREMENT)
+
+    $dataFeedLineTop = offset_to_viewport_line_number(
+      offsetArg,
+      $bytesPerRow,
+      fetchOffset
+    )
+
+    vscode.postMessage({
+      command: MessageCommand.scrollViewport,
+      data: {
+        scrollOffset: fetchOffset,
+        bytesPerRow: $bytesPerRow,
+        numLinesDisplayed: $viewportNumLinesDisplayed,
+      },
+    })
     clearDataDisplays()
   }
 
@@ -175,10 +172,12 @@ limitations under the License.
   }
 
   function handleEditorEvent(_: Event) {
-    if ($selectionSize < 0) {
+    if ($regularSizedFile && $selectionSize < 0) {
       clearDataDisplays()
       return
     }
+    if (!$regularSizedFile && $editorSelection.length == 0) return
+
     requestEditedData()
   }
 
@@ -187,7 +186,9 @@ limitations under the License.
 
     let editedData: Uint8Array
     let originalData = $originalDataSegment
-    let editedOffset = $selectionDataStore.startOffset + $viewport.fileOffset
+    let editedOffset = $regularSizedFile
+      ? $selectionDataStore.startOffset + $viewport.fileOffset
+      : 0
 
     // noinspection FallThroughInSwitchStatementJS
     switch (action) {
@@ -200,7 +201,10 @@ limitations under the License.
         editedData = $editedDataSegment.subarray(0, 1)
         break
       case 'insert-replace':
-        editedData = $editedDataSegment
+        editedData =
+          !$regularSizedFile && $editorSelection.length == 0
+            ? new Uint8Array(0)
+            : $editedDataSegment
         break
       case 'delete':
         editedData = new Uint8Array(0)
diff --git a/src/svelte/src/stores/index.ts b/src/svelte/src/stores/index.ts
index 39add99..185cba1 100644
--- a/src/svelte/src/stores/index.ts
+++ b/src/svelte/src/stores/index.ts
@@ -89,9 +89,6 @@ export const dataViewEndianness = writable('le')
 // radix to use for displaying raw bytes (2, 8, 10, 16)
 export const displayRadix = writable(16 as RadixValues)
 
-// true if the edit byte window is hidden
-export const editByteWindowHidden = writable(true)
-
 // segment of data that is being edited in single or multiple byte modes
 export const editedDataSegment = writable(new Uint8Array(0))
 
@@ -108,8 +105,12 @@ export const seekOffsetInput = writable('')
 // writeable boolean, true indicates that the search is case insensitive for character sets that support it
 export const searchCaseInsensitive = writable(false)
 
+// Current viewport line number at the top of the data display
 export const dataFeedLineTop = writable(0)
+
+// Data display needs to wait from data from extension or function
 export const dataFeedAwaitRefresh = writable(false)
+
 export const rerenderActionElements = writable(false)
 
 // Viewport properties
@@ -124,6 +125,7 @@ export const selectedByte = writable({
   value: -1,
 } as ByteValue)
 
+// Omega Edit and Data Editor file information
 export const fileMetrics = new FileMetrics()
 
 export const searchQuery = new SearchQuery()
@@ -133,13 +135,21 @@ export const searchErr = new ErrorStore(ErrorComponentType.SYMBOL)
 export const replaceErr = new ErrorStore(ErrorComponentType.SYMBOL)
 export const seekErr = new ErrorStore(ErrorComponentType.SYMBOL)
 
+// Which types of edit restrictions are in place
 export const editorActionsAllowed = writable(EditActionRestrictions.None)
 export const tooltipsEnabled = writable(false)
+
+// If byte lengths should be in a human readable format
 export const sizeHumanReadable = writable(false)
 
 // tracks the start and end offsets of the current selection
 export const selectionDataStore = new SelectionData()
 
+// Can the user's selection derive both edit modes?
+export const regularSizedFile = derived(fileMetrics, ($fileMetrics) => {
+  return $fileMetrics.computedSize >= 2
+})
+
 export const searchable = derived(
   [searchQuery, editorEncoding],
   ([$searchQuery, $editorEncoding]) => {
@@ -187,8 +197,10 @@ export const replaceable = derived(
 
 // derived readable enumeration that indicates the edit mode (single byte or multiple bytes)
 export const editMode = derived(
-  selectionDataStore,
-  ($selectionData) => {
+  [selectionDataStore, regularSizedFile],
+  ([$selectionData, $regularSizedFile]) => {
+    if (!$regularSizedFile) return EditByteModes.Multiple
+
     return $selectionData.originalEndOffset - $selectionData.startOffset === 0
       ? EditByteModes.Single
       : EditByteModes.Multiple
@@ -211,7 +223,7 @@ export const seekOffset = derived(
   [seekOffsetInput, addressRadix],
   ([$seekOffsetInput, $addressRadix]) => {
     return $seekOffsetInput.length > 0
-      ? parseInt($seekOffsetInput, $addressRadix)
+      ? Math.max(0, parseInt($seekOffsetInput, $addressRadix))
       : 0
   }
 )
@@ -277,19 +289,21 @@ export const requestable = derived(
     applyErrMsg.update(() => {
       return ret.errMsg
     })
+
     return ret.valid
   }
 )
 
 export const originalDataSegment = derived(
-  [viewport, selectionDataStore],
-  ([$viewport, $selectionData]) => {
-    return !$viewport.data
-      ? []
-      : $viewport.data.slice(
-          $selectionData.startOffset,
-          $selectionData.originalEndOffset + 1
-        )
+  [viewport, selectionDataStore, regularSizedFile],
+  ([$viewport, $selectionData, $regularSizedFile]) => {
+    if (!$viewport.data) return []
+    if (!$regularSizedFile) return $viewport.data
+
+    return $viewport.data.slice(
+      $selectionData.startOffset,
+      $selectionData.originalEndOffset + 1
+    )
   }
 )
 
@@ -298,23 +312,36 @@ export const applicable = derived(
   [
     requestable,
     viewport,
+    editorSelection,
+    displayRadix,
     editedDataSegment,
     selectionDataStore,
     selectionSize,
     editMode,
     editedByteIsOriginalByte,
     editorActionsAllowed,
+    regularSizedFile,
   ],
   ([
     $requestable,
     $viewport,
+    $editorSelection,
+    $displayRadix,
     $selectedFileData,
     $selectionData,
     $selectionSize,
     $editMode,
     $editedByteIsOriginalByte,
     $editorActionsAllowed,
+    $regularSizedFile,
   ]) => {
+    if (!$regularSizedFile) {
+      return $viewport.data.length !=
+        $editorSelection.length / radixBytePad($displayRadix) &&
+        $editorActionsAllowed === EditActionRestrictions.OverwriteOnly
+        ? false
+        : $requestable
+    }
     if (
       !$requestable ||
       ($editedByteIsOriginalByte && $editMode === EditByteModes.Single)
diff --git a/src/svelte/src/utilities/display.ts b/src/svelte/src/utilities/display.ts
index a9edc4b..6b0f522 100644
--- a/src/svelte/src/utilities/display.ts
+++ b/src/svelte/src/utilities/display.ts
@@ -37,10 +37,6 @@ const ByteDivWidths = {
   2: '64px' as ByteDivWidth,
 }
 
-export type BinaryBytePrefix = 'B' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB'
-
-export type BinaryBitPrefix = 'b' | 'Kb' | 'Mb' | 'Gb' | 'Tb' | 'Pb'
-
 export function radixBytePad(radix: RadixValues): number {
   switch (radix) {
     case 2:
@@ -181,7 +177,17 @@ export function viewport_offset_to_line_num(
   vpStartOffset: number,
   bytesPerRow: BytesPerRow
 ): number {
-  return Math.floor((offset - vpStartOffset) / bytesPerRow)
+  return Math.max(0, Math.floor((offset - vpStartOffset) / bytesPerRow))
+}
+
+export function line_num_to_file_offset(
+  lineNum: number,
+  viewportStartOffset: number,
+  bytesPerRow: BytesPerRow
+): number {
+  const offsetInViewport = lineNum * bytesPerRow
+  const offsetInFile = viewportStartOffset + offsetInViewport
+  return Math.max(0, offsetInFile)
 }
 
 export enum BinaryBytePrefixes {
diff --git a/src/svelte/src/utilities/elementKeypressEvents.ts b/src/svelte/src/utilities/elementKeypressEvents.ts
index 8cbabc8..5d266b7 100644
--- a/src/svelte/src/utilities/elementKeypressEvents.ts
+++ b/src/svelte/src/utilities/elementKeypressEvents.ts
@@ -26,7 +26,6 @@ type ElementKeypressEvent = {
 }
 
 class ElementKeypressEventMap {
-  // private events: Array<ElementKeypressEvent> = []
   private events: {
     [key in ElementKeypressEventKey]: Array<ElementKeypressEvent>
   } = {
diff --git a/src/svelte/src/utilities/highlights.ts b/src/svelte/src/utilities/highlights.ts
index 1ceeb44..bb00644 100644
--- a/src/svelte/src/utilities/highlights.ts
+++ b/src/svelte/src/utilities/highlights.ts
@@ -50,6 +50,7 @@ export const selectionHighlights = derived(
 )
 
 export const searchResultsHighlights = readable(searchResultsHighlightLUT)
+export const searchResultsUpdated = writable(false)
 export function updateSearchResultsHighlights(
   data: number[],
   viewportFileOffset: number,
@@ -68,6 +69,7 @@ export function updateSearchResultsHighlights(
     for (let i = 0; i < byteWidth; i++)
       searchResultsHighlightLUT[offset - viewportFileOffset + i] = 1
   })
+  searchResultsUpdated.set(true)
 }
 export function clearSearchResultsHighlights() {
   searchResultsHighlightLUT.fill(0)