g | x | w | all
Bytes Lang Time Link
088Charcoal230725T084921ZNeil
145Ruby230725T042530ZValue In
228Python 3.8 prerelease230725T041111ZEthan C
248Q230724T171115Zscottste

Charcoal, 88 bytes

Sθ≔⁻LθNηWS≡ι´⟲≔∧υ⊟υι⊞υιFυ≡ι´←≧⁺‹ηLθη´→≧⁻‹⁰ηη´⮌≔⁺✂θ⁰±⊕η¹✂θ⁻LθηLθ¹θ≔⁺⁺✂θ⁰⁻Lθη¹ι✂θ⁻LθηLθ¹θθ

Try it online! Link is to verbose version of code. Takes the input sequence as a list of newline-terminated strings where is undo, is left, is right, and is backspace. Explanation:

Sθ≔⁻LθNη

Input the starting string and position, but calculate the position as a count from the end of the string, because that remains invariant under insertion and deletion.

WS

Loop through each command string.

≡ι´⟲≔∧υ⊟υι⊞υι

If it's a then remove the previous command if any otherwise add the command.

Fυ≡ι

Loop through the remaining commands.

´←≧⁺‹ηLθη

Handle left.

´→≧⁻‹⁰ηη

Handle right.

´⮌≔⁺✂θ⁰±⊕η¹✂θ⁻LθηLθ¹θ

Handle backspace.

≔⁺⁺✂θ⁰⁻Lθη¹ι✂θ⁻LθηLθ¹θ

Handle everything else.

θ

Output the resulting string.

Ruby, 145 bytes

Not sure if it breaks the rules to have the special commands as integers. U=0, L=-1, R=1, B=8

The only reason B=8 is because the control code for backspace is \x08 lol

->s,l,i{i[(x=i.index 0)-[1,x].min..x]=[]while[]!=[0]&i
i.map{|e|l=l.clamp 0,s.size;e.ord==e ?e<5?l+=e:(s[l-=1]=''if l>0):(s[l,0]=e;l+=e.size)}
s}

Try it online!

Ruby, 153 bytes

Version that uses characters only in case the above answer breaks the rules: U=\x00, L=\x01, R=\x03, B=\x08

->s,l,i{i[(x=i.index"\0")-[1,x].min..x]=[]while[]!=[?\0]&i
i.map{|e|l=l.clamp 0,s.size;c=e.ord;c<9?c<5?l+=c-2:(s[l-=1]=''if l>0):(s[l,0]=e;l+=e.size)}
s}

Python 3.8 (pre-release), 228 bytes

def f(s,c,Z,d=[]):
 for i in Z:d=d[:-1]if i[0]and'T'<i[1]else d+[i]
 for S,D in d:
  if S:
   if'Q'<D:c=min(c+1,len(s))
   elif'K'<D:c=max(c-1,0)
   else:s=s[:(f:=max(c-1,0))]+s[c:];c=f
  else:s=s[:c]+D+s[c:];c+=len(D)
 return s

Try it online!

The first for loop uses the stack d to get rid of all the undos. The second for loop loops over each instruction and modifies the string s accordingly. Almost definitely still golfable.

Inputs: list of tuples: (opcode, string). The opcode is 1 if the string is a special command, and 0 otherwise. Ex: [(1, 'R'), (1, 'U'), (0, 'hi')] This may be stretching the acceptable input format a bit, so I made a version which can accept the input format that the OP used:

Python 3.8 (pre-release), 267 bytes

def f(s,c,Z,d=[]):
 for i in Z.split(';'):g='['in i;i=i[1]if g else i;d=d[:-1]if g and'T'<i else d+[(g,i)]
 for S,D in d:
  if S:
   if'Q'<D:c=min(c+1,len(s))
   elif'K'<D:c=max(c-1,0)
   else:s=s[:(f:=max(c-1,0))]+s[c:];c=f
  else:s=s[:c]+D+s[c:];c+=len(D)
 return s

Try it online!

Q, 248 bytes

w:{s:{x like"[[]",y,"[]]"};if[10=(@:)z;z:";"vs z];while[z[0]~"[U]";z:1_z];$[0=(#:)z;x;not(^:)r:(*:)(&:)s[z;"U"];w[x;y;_[z _ r;r-1]];s[o:z 0;"R"];w[x;(#:)[x]&y+1;1_z];s[o;"L"];w[x;0|y-1;1_z];s[o;"B"];w[x _ y-1;0|y-1;1_z];w[#[y;x],o,_[y;x];y+1;1_z]]}

ungolfed:

wp: { [text; cursor; input]
    if[10h=type input; input: ";" vs input];                    // convert semicolon-delimited string to list of strings
    special: {x like "[[]",y,"[]]"};                            // function to check whether a string is like e.g. "[E]"
    while[input[0]~"[U]"; input: 1 _ input];                    // remove leading undo's since there's nothing to undo
    if[not null rm: first where special[input; "U"];            // find the first "[U]" operation -- re-call this function after removing it and the preceding operation
        : wp[text; cursor; _[input _ rm;rm-1]];
    ];
    if[0=count input; : text];                                  // base case -- return text if there are no more operations
    op: input 0;
    if[special[op; "R"];                                        // re-call this function with 1 added to cursor (capping at length of text)
        : wp[text; count[text]&cursor+1; 1_input]];
    if[special[op; "L"];                                        // re-call this function with 1 removed from the cursor (capping at 0)
        : wp[text; 0|cursor-1; 1_input]];
    if[special[op; "B"];                                        // re-call this function with a) the character before the cursor removed from text and b) 1 removed from the cursor (capping at 0)
        : wp[text _ cursor-1; 0|cursor-1; 1_input]];
    : wp[ #[cursor;text],op,_[cursor;text]; cursor+1; 1_input]; // re-call this function with the characters added after the cursor in text
    }