9fans.net/go@v0.0.7/cmd/acme/internal/file/file.go (about)

     1  // #include <u.h>
     2  // #include <libc.h>
     3  // #include <draw.h>
     4  // #include <thread.h>
     5  // #include <cursor.h>
     6  // #include <mouse.h>
     7  // #include <keyboard.h>
     8  // #include <frame.h>
     9  // #include <fcall.h>
    10  // #include <plumb.h>
    11  // #include <libsec.h>
    12  // #include "dat.h"
    13  // #include "fns.h"
    14  
    15  /*
    16   * Structure of Undo list:
    17   * 	The Undo structure follows any associated data, so the list
    18   *	can be read backwards: read the structure, then read whatever
    19   *	data is associated (insert string, file name) and precedes it.
    20   *	The structure includes the previous value of the modify bit
    21   *	and a sequence number; successive Undo structures with the
    22   *	same sequence number represent simultaneous changes.
    23   */
    24  
    25  package file
    26  
    27  import (
    28  	"fmt"
    29  	"os"
    30  	"reflect"
    31  	"unsafe"
    32  
    33  	"9fans.net/go/cmd/acme/internal/bufs"
    34  	"9fans.net/go/cmd/acme/internal/disk"
    35  	"9fans.net/go/cmd/acme/internal/runes"
    36  	"9fans.net/go/cmd/acme/internal/util"
    37  )
    38  
    39  type File struct {
    40  	view    View
    41  	b       disk.Buffer
    42  	delta   disk.Buffer
    43  	epsilon disk.Buffer
    44  	name    []rune
    45  	seq     int
    46  	mod     bool
    47  }
    48  
    49  func (f *File) SetView(v View) { f.view = v }
    50  
    51  type View interface {
    52  	Insert(int, []rune)
    53  	Delete(int, int)
    54  }
    55  
    56  const (
    57  	typeEmpty    = 0
    58  	typeNull     = '-'
    59  	typeDelete   = 'd'
    60  	typeInsert   = 'i'
    61  	typeReplace  = 'r'
    62  	typeFilename = 'f'
    63  )
    64  
    65  type undo struct {
    66  	typ int
    67  	mod bool
    68  	seq int
    69  	p0  int
    70  	n   int
    71  }
    72  
    73  const undoSize = int(unsafe.Sizeof(undo{})) / runes.RuneSize
    74  
    75  func undorunes(u *undo) []rune {
    76  	var r []rune
    77  	h := (*reflect.SliceHeader)(unsafe.Pointer(&r))
    78  	h.Data = uintptr(unsafe.Pointer(u))
    79  	h.Len = undoSize
    80  	h.Cap = undoSize
    81  	return r
    82  }
    83  
    84  func (f *File) Len() int { return f.b.Len() }
    85  
    86  func (f *File) CanUndo() bool { return f.delta.Len() > 0 }
    87  
    88  func (f *File) CanRedo() bool { return f.epsilon.Len() > 0 }
    89  
    90  func (f *File) Mod() bool { return f.mod }
    91  
    92  func (f *File) SetMod(b bool) { f.mod = b }
    93  
    94  var Seq int
    95  
    96  func (f *File) Seq() int { return f.seq }
    97  
    98  func (f *File) SetSeq(seq int) { f.seq = seq }
    99  
   100  func (f *File) Mark() {
   101  	if f.epsilon.Len() != 0 {
   102  		f.epsilon.Delete(0, f.epsilon.Len())
   103  	}
   104  	f.seq = Seq
   105  }
   106  
   107  func (f *File) Read(pos int, data []rune) { f.b.Read(pos, data) }
   108  
   109  func (f *File) Insert(p0 int, s []rune) {
   110  	if p0 > f.b.Len() {
   111  		util.Fatal("internal error: fileinsert")
   112  	}
   113  	if f.seq > 0 {
   114  		f.uninsert(&f.delta, p0, len(s))
   115  	}
   116  	f.b.Insert(p0, s)
   117  	if len(s) != 0 {
   118  		f.mod = true
   119  	}
   120  }
   121  
   122  func (f *File) uninsert(delta *disk.Buffer, p0, ns int) {
   123  	var u undo
   124  	/* undo an insertion by deleting */
   125  	u.typ = typeDelete
   126  	u.mod = f.mod
   127  	u.seq = f.seq
   128  	u.p0 = p0
   129  	u.n = ns
   130  	delta.Insert(delta.Len(), undorunes(&u))
   131  }
   132  
   133  func (f *File) Delete(p0, p1 int) {
   134  	if !(p0 <= p1 && p0 <= f.b.Len()) || !(p1 <= f.b.Len()) {
   135  		util.Fatal("internal error: filedelete")
   136  	}
   137  	if f.seq > 0 {
   138  		f.undelete(&f.delta, p0, p1)
   139  	}
   140  	f.b.Delete(p0, p1)
   141  	if p1 > p0 {
   142  		f.mod = true
   143  	}
   144  }
   145  
   146  func (f *File) undelete(delta *disk.Buffer, p0, p1 int) {
   147  	var u undo
   148  	/* undo a deletion by inserting */
   149  	u.typ = typeInsert
   150  	u.mod = f.mod
   151  	u.seq = f.seq
   152  	u.p0 = p0
   153  	u.n = p1 - p0
   154  	buf := bufs.AllocRunes()
   155  	var n int
   156  	for i := p0; i < p1; i += n {
   157  		n = p1 - i
   158  		if n > bufs.RuneLen {
   159  			n = bufs.RuneLen
   160  		}
   161  		f.b.Read(i, buf[:n])
   162  		delta.Insert(delta.Len(), buf[:n])
   163  	}
   164  	bufs.FreeRunes(buf)
   165  	delta.Insert(delta.Len(), undorunes(&u))
   166  }
   167  
   168  func (f *File) Name() []rune { return f.name }
   169  
   170  func (f *File) SetName(name []rune) {
   171  	if f.seq > 0 {
   172  		f.unsetname(&f.delta)
   173  	}
   174  	f.name = runes.Clone(name)
   175  }
   176  
   177  func (f *File) unsetname(delta *disk.Buffer) {
   178  	var u undo
   179  	/* undo a file name change by restoring old name */
   180  	u.typ = typeFilename
   181  	u.mod = f.mod
   182  	u.seq = f.seq
   183  	u.p0 = 0 /* unused */
   184  	u.n = len(f.name)
   185  	if len(f.name) != 0 {
   186  		delta.Insert(delta.Len(), f.name)
   187  	}
   188  	delta.Insert(delta.Len(), undorunes(&u))
   189  }
   190  
   191  /* return sequence number of pending redo */
   192  func (f *File) RedoSeq() int {
   193  	delta := &f.epsilon
   194  	if delta.Len() == 0 {
   195  		return 0
   196  	}
   197  	var u undo
   198  	delta.Read(delta.Len()-undoSize, undorunes(&u))
   199  	return u.seq
   200  }
   201  
   202  func (f *File) Undo(isundo bool, q0p, q1p *int) {
   203  	var stop int
   204  	var delta *disk.Buffer
   205  	var epsilon *disk.Buffer
   206  	if isundo {
   207  		/* undo; reverse delta onto epsilon, seq decreases */
   208  		delta = &f.delta
   209  		epsilon = &f.epsilon
   210  		stop = f.seq
   211  	} else {
   212  		/* redo; reverse epsilon onto delta, seq increases */
   213  		delta = &f.epsilon
   214  		epsilon = &f.delta
   215  		stop = 0 /* don't know yet */
   216  	}
   217  
   218  	buf := bufs.AllocRunes()
   219  	for delta.Len() > 0 {
   220  		up := delta.Len() - undoSize
   221  		var u undo
   222  		delta.Read(up, undorunes(&u))
   223  		if isundo {
   224  			if u.seq < stop {
   225  				f.seq = u.seq
   226  				goto Return
   227  			}
   228  		} else {
   229  			if stop == 0 {
   230  				stop = u.seq
   231  			}
   232  			if u.seq > stop {
   233  				goto Return
   234  			}
   235  		}
   236  		var n int
   237  		var i int
   238  		switch u.typ {
   239  		default:
   240  			fmt.Fprintf(os.Stderr, "undo: %#x\n", u.typ)
   241  			panic("undo")
   242  
   243  		case typeDelete:
   244  			f.seq = u.seq
   245  			f.undelete(epsilon, u.p0, u.p0+u.n)
   246  			f.mod = u.mod
   247  			f.b.Delete(u.p0, u.p0+u.n)
   248  			f.view.Delete(u.p0, u.p0+u.n)
   249  			*q0p = u.p0
   250  			*q1p = u.p0
   251  
   252  		case typeInsert:
   253  			f.seq = u.seq
   254  			f.uninsert(epsilon, u.p0, u.n)
   255  			f.mod = u.mod
   256  			up -= u.n
   257  			for i = 0; i < u.n; i += n {
   258  				n = u.n - i
   259  				if n > bufs.RuneLen {
   260  					n = bufs.RuneLen
   261  				}
   262  				delta.Read(up+i, buf[:n])
   263  				f.b.Insert(u.p0+i, buf[:n])
   264  				f.view.Insert(u.p0+i, buf[:n])
   265  			}
   266  			*q0p = u.p0
   267  			*q1p = u.p0 + u.n
   268  
   269  		case typeFilename:
   270  			f.seq = u.seq
   271  			f.unsetname(epsilon)
   272  			f.mod = u.mod
   273  			up -= u.n
   274  			if u.n == 0 {
   275  				f.name = nil
   276  			} else {
   277  				f.name = make([]rune, u.n)
   278  			}
   279  			delta.Read(up, f.name)
   280  		}
   281  		delta.Delete(up, delta.Len())
   282  	}
   283  	if isundo {
   284  		f.seq = 0
   285  	}
   286  Return:
   287  	bufs.FreeRunes(buf)
   288  }
   289  
   290  func (f *File) ResetLogs() {
   291  	f.delta.Reset()
   292  	f.epsilon.Reset()
   293  	f.seq = 0
   294  }
   295  
   296  func (f *File) Truncate() { f.b.Reset() }
   297  
   298  func (f *File) Close() {
   299  	f.name = nil
   300  	f.view = nil
   301  	f.b.Close()
   302  	f.delta.Close()
   303  	f.epsilon.Close()
   304  }