diff --git a/ivette/src/dome/renderer/text/editor.tsx b/ivette/src/dome/renderer/text/editor.tsx
index 64287c759db94780319661e5ab589b55312e9d2a..c2f6cbdab5357bb7eeecb42f8f8ad5b035a8da75 100644
--- a/ivette/src/dome/renderer/text/editor.tsx
+++ b/ivette/src/dome/renderer/text/editor.tsx
@@ -24,6 +24,7 @@ import React from 'react';
 
 import { EditorState, StateField, Facet, Extension } from '@codemirror/state';
 import { Annotation, Transaction, RangeSet } from '@codemirror/state';
+import { EditorSelection, AnnotationType } from '@codemirror/state';
 
 import { EditorView, ViewPlugin, ViewUpdate } from '@codemirror/view';
 import { Decoration, DecorationSet } from '@codemirror/view';
@@ -55,7 +56,8 @@ export type View = EditorView | null;
 export type Range = { from: number, to: number };
 export type Set<A> = (view: View, value: A) => void;
 export type Get<A> = (state: EditorState | undefined) => A;
-export interface Data<A, S> { init: A, get: Get<A>, structure: S }
+export interface Structure<S> { structure: S, extension: Extension }
+export interface Data<A, S> extends Structure<S> { init: A, get: Get<A> }
 
 // Event handlers type definition.
 export type Handler<I, E> = (i: I, v: EditorView, e: E) => void;
@@ -70,7 +72,7 @@ export type Handlers<I> = { [e in keyof EventMap]?: Handler<I, EventMap[e]> };
 // structure is exposed for two reasons. The first one is that it contains the
 // extension that must be added to the CodeMirror instanciation. The second one
 // is that it is needed during the Aspects creation's process.
-export interface Field<A> extends Data<A, StateField<A>> { set: Set<A> }
+export interface Field<A> extends Data<A, StateField<A>> { set: Set<A>, annotation: AnnotationType<A> }
 
 // An Aspect is a data associated with an editor state and computed by combining
 // data from several fields. A typical use case is if one needs a data that
@@ -79,7 +81,7 @@ export interface Field<A> extends Data<A, StateField<A>> { set: Set<A> }
 // information of CodeMirror) is changed. An Aspect exposes a getter that
 // handles all React's hooks shenanigans and an extension that must be added to
 // the CodeMirror initial configuration.
-export interface Aspect<A> extends Data<A, Facet<A, A>> { extension: Extension }
+export interface Aspect<A> extends Data<A, Facet<A, A>> {}
 
 // State extensions and Aspects have to declare their dependencies, i.e. the
 // Field and Aspects they rely on to perform their computations. Dependencies
@@ -128,15 +130,6 @@ function inputs<I extends Dict>(ds: Deps<I>, s: EditorState | undefined): Dict {
   return transformDict(ds, (d) => d.get(s));
 }
 
-// Helper function retrieving a dependency extension.
-function getExtension<A>(dep: Dependency<A>): Extension {
-  type Dep<A> = Dependency<A>;
-  const asExt = (d: Dep<A>): boolean => Object.keys(d).includes('extension');
-  const isAspect = (d: Dep<A>): d is Aspect<A> => asExt(d);
-  if (isAspect(dep)) return dep.extension;
-  else return dep.structure.extension;
-}
-
 // -----------------------------------------------------------------------------
 
 
@@ -170,9 +163,8 @@ export function createField<A>(init: A): Field<A> {
   const update: Update<A> = (current, tr) => tr.annotation(annot) ?? current;
   const field = StateField.define<A>({ create, update });
   const get: Get<A> = (state) => state?.field(field) ?? init;
-  const useSet: Set<A> = (v, a) =>
-    React.useEffect(() => v?.dispatch({ annotations: annot.of(a) }), [v, a]);
-  return { init, get, set: useSet, structure: field };
+  const set: Set<A> = (v, a) => v?.dispatch({ annotations: annot.of(a) });
+  return { init, get, set, structure: field, extension: field, annotation: annot };
 }
 
 // An Aspect is declared using its dependencies and a function. This function's
@@ -183,7 +175,7 @@ export function createAspect<I extends Dict, O>(
   deps: Dependencies<I>,
   fn: (input: I) => O,
 ): Aspect<O> {
-  const enables = mapDict(deps, getExtension);
+  const enables = mapDict(deps, (d) => d.extension);
   const init = fn(transformDict(deps, (d) => d.init) as I);
   const combine: Combine<O> = (l) => l.length > 0 ? l[l.length - 1] : init;
   const facet = Facet.define<O, O>({ combine, enables });
@@ -201,7 +193,7 @@ export function createDecorator<I extends Dict>(
   deps: Dependencies<I>,
   fn: (inputs: I, state: EditorState) => DecorationSet
 ): Extension {
-  const enables = mapDict(deps, getExtension);
+  const enables = mapDict(deps, (d) => d.extension);
   const get = (s: EditorState): DecorationSet => fn(inputs(deps, s) as I, s);
   class S { s: DecorationSet = RangeSet.empty; }
   class D extends S { update(u: ViewUpdate): void { this.s = get(u.state); } }
@@ -217,7 +209,7 @@ export function createGutter<I extends Dict>(
   className: string,
   line: (inputs: I, block: Range, view: EditorView) => GutterMarker | null
 ): Extension {
-  const enables = mapDict(deps, getExtension);
+  const enables = mapDict(deps, (d) => d.extension);
   const extension = gutter({
     class: className,
     lineMarker: (view, block) => {
@@ -250,7 +242,7 @@ export function createEventHandler<I extends Dict>(
   deps: Dependencies<I>,
   handlers: Handlers<I>,
 ): Extension {
-  const enables = mapDict(deps, getExtension);
+  const enables = mapDict(deps, (d) => d.extension);
   const domEventHandlers = Object.fromEntries(Object.keys(handlers).map((k) => {
     const h = handlers[k] as Handler<I, typeof k>;
     const fn = (e: typeof k, v: EditorView): void =>
@@ -260,6 +252,10 @@ export function createEventHandler<I extends Dict>(
   return enables.concat(EditorView.domEventHandlers(domEventHandlers));
 }
 
+export function createUpdater(fn: (update: ViewUpdate) => void): Extension {
+  return EditorView.updateListener.of(fn);
+}
+
 // -----------------------------------------------------------------------------
 
 
@@ -304,20 +300,32 @@ export const LanguageHighlighter: Extension =
 //  Standard extensions and commands
 // -----------------------------------------------------------------------------
 
+export const Selection = createSelectionField();
+function createSelectionField(): Field<EditorSelection> {
+  const cursor = EditorSelection.cursor(0);
+  const field = createField<EditorSelection>(EditorSelection.create([cursor]));
+  const set: Set<EditorSelection> = (view, selection) => {
+    field.set(view, selection);
+    view?.dispatch({ selection });
+  }
+  const updater = EditorView.updateListener.of((update) => {
+    if (update.selectionSet) field.set(update.view, update.state.selection);
+  });
+  return { ...field, set, extension: [field.extension, updater] };
+}
+
 // Create a text field that updates the CodeMirror document when set.
 export type ToString<A> = (text: A) => string;
 export function createTextField<A>(init: A, toString: ToString<A>): Field<A> {
   const field = createField<A>(init);
-  const useSet: Set<A> = (view, text) => {
+  const set: Set<A> = (view, text) => {
     field.set(view, text);
-    React.useEffect(() => {
-      const selection = { anchor: 0 };
-      const length = view?.state.doc.length;
-      const changes = { from: 0, to: length, insert: toString(text) };
-      view?.dispatch({ changes, selection });
-    }, [view, text]);
+    const selection = { anchor: 0 };
+    const length = view?.state.doc.length;
+    const changes = { from: 0, to: length, insert: toString(text) };
+    view?.dispatch({ changes, selection });
   };
-  return { ...field, set: useSet };
+  return { ...field, set };
 }
 
 // An extension displaying line numbers in a gutter. Does not display anything
@@ -375,6 +383,14 @@ export function selectLine(view: View, line: number, atTop: boolean): void {
   view.dispatch({ effects });
 }
 
+export const TransactionExtenderTest = createTest();
+function createTest(): Extension {
+  return EditorState.transactionExtender.of((transaction) => {
+    console.log(transaction);
+    return null;
+  });
+}
+
 // -----------------------------------------------------------------------------
 
 
diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx
index f52c60997293e9ab52c3ecae6757ed502ac7e620..ac8f6105960d1bfedd37e5d2a28afff3d3604b3d 100644
--- a/ivette/src/frama-c/kernel/ASTview.tsx
+++ b/ivette/src/frama-c/kernel/ASTview.tsx
@@ -62,7 +62,7 @@ type Range = Editor.Range;
 function isDef<A>(a: A | undefined): a is A { return a !== undefined; }
 
 // Map a function over a list, removing all inputs that returned undefined.
-function mapFilter<A, B>(xs: A[], fn: (x: A) => B | undefined): B[] {
+function mapFilter<A, B>(xs: readonly A[], fn: (x: A) => B | undefined): B[] {
   return xs.map(fn).filter(isDef);
 }
 
@@ -149,6 +149,27 @@ function coveringNode(tree: Tree, pos: number): Node | undefined {
 // -----------------------------------------------------------------------------
 
 
+/*
+function useViewState() {
+  const [selection, updateSelection] = States.useSelection();
+  const [hovered, updateHovered] = States.useHovered();
+  const selected = selection?.current?.marker;
+  const fct = selection?.current?.fct;
+
+  const text = States.useRequest(Ast.printFunction, fct) ?? null;
+  const tree = React.useMemo(() => textToTree(text) ?? empty, [text]);
+  const ranges = React.useMemo(() => markersRanges(tree), [tree]);
+  const code = React.useMemo(() => textToString(text), [text]);
+
+  const emptyDead = { unreachable: [], nonTerminating: [] };
+  const dead = States.useRequest(Eva.getDeadCode, fct) ?? emptyDead;
+  const tags = States.useTags(Properties.propStatusTags);
+  const propertiesStatuses = States.useSyncArray(Properties.status).getArray();
+
+
+}
+*/
+
 
 // -----------------------------------------------------------------------------
 //  Function code representation
@@ -204,18 +225,38 @@ function createMarkerUpdater(): Editor.Extension {
   });
 }
 
+const MarkerScroller = Editor.createUpdater((update) => {
+  console.log(update);
+  const a = Marker.annotation;
+  const markers = mapFilter(update.transactions, (tr) => tr.annotation(a));
+  if (markers.length !== 1) return;
+  const marker = markers[0];
+  const selection = update.state.selection.main;
+  const ranges = Ranges.get(update.state).get(marker) ?? [];
+  if (ranges.length !== 1) { console.log(ranges); return; }
+  if (ranges[0] === selection) return;
+  const { from: anchor } = ranges[0];
+  update.view.dispatch({ selection: { anchor }, scrollIntoView: true });
+});
+
+
+/*
 // Scroll the selected marker into view if needed. Used for when the marker is
 // changed outside of this component.
 function scrollMarkerIntoView(view: Editor.View, marker: Marker): void {
   if (!view || !marker) return;
   const selection = view.state.selection.main;
+  console.log('-- Marker: ', marker);
   const ranges = Ranges.get(view.state).get(marker) ?? [];
+  console.log('-- Ranges: ', ranges);
   if (ranges.length === 0) return;
   const exists = ranges.find((range) => range === selection);
+  console.log('-- Exists: ', exists);
   if (exists) return;
   const { from: anchor } = ranges[0];
   view.dispatch({ selection: { anchor }, scrollIntoView: true });
 }
+*/
 
 // -----------------------------------------------------------------------------
 
@@ -597,7 +638,10 @@ function useFctDead(fct: Fct): Eva.deadCode {
 // Server request handler returning the given function's callers.
 function useFctCallers(fct: Fct): Caller[] {
   const callers = States.useRequest(Eva.getCallers, fct) ?? [];
-  return callers.map(([fct, marker]) => ({ fct, marker }));
+  const res = React.useMemo(() => {
+    return callers.map(([fct, marker]) => ({ fct, marker }))
+  }, [callers]);
+  return res;
 }
 
 // Server request handler returning the tainted lvalues.
@@ -616,6 +660,7 @@ function useFctTaints(fct: Fct): Eva.LvalueTaints[] {
 // Necessary extensions for our needs.
 const extensions: Editor.Extension[] = [
   MarkerUpdater,
+  // MarkerScroller,
   HoveredUpdater,
   CodeDecorator,
   DeadCodeDecorator,
@@ -625,6 +670,7 @@ const extensions: Editor.Extension[] = [
   TaintTooltip,
   Editor.FoldGutter,
   Editor.LanguageHighlighter,
+  Editor.TransactionExtenderTest,
 ];
 
 // The component in itself.
@@ -633,38 +679,44 @@ export default function ASTview(): JSX.Element {
   const { view, Component } = Editor.Editor(extensions);
 
   // Updating CodeMirror when the selection or its callback are changed.
-  const [selection, updateSelection] = States.useSelection();
-  UpdateSelection.set(view, updateSelection);
+  const [selection, setSel] = States.useSelection();
+  React.useEffect(() => UpdateSelection.set(view, setSel), [view, setSel]);
+  const fct = selection?.current?.fct;
+  React.useEffect(() => Fct.set(view, fct), [view, fct]);
+  const marker = selection?.current?.marker;
+  React.useEffect(() => Marker.set(view, marker), [view, marker]);
 
   // Updating CodeMirror when the <updateHovered> callback is changed.
-  const [hovered, updateHovered] = States.useHovered();
-  UpdateHovered.set(view, updateHovered);
+  const [hov, setHov] = States.useHovered();
+  React.useEffect(() => UpdateHovered.set(view, setHov), [view, setHov]);
+  React.useEffect(() => Hovered.set(view, hov?.marker ?? ''), [view, hov]);
 
   // Updating CodeMirror when the <properties> synchronized array is changed.
-  const properties = States.useSyncArray(Properties.status).getArray();
-  PropertiesStatuses.set(view, properties);
+  const props = States.useSyncArray(Properties.status).getArray();
+  React.useEffect(() => PropertiesStatuses.set(view, props), [view, props]);
 
   // Updating CodeMirror when the <propStatusTags> map is changed.
   const tags = States.useTags(Properties.propStatusTags);
-  Tags.set(view, tags);
+  React.useEffect(() => Tags.set(view, tags), [view, tags]);
 
   // Updating CodeMirror when the <markersInfo> synchronized array is changed.
   const info = States.useSyncArray(Ast.markerInfo);
-  const getMarkerData = React.useCallback((key) => info.getData(key), [info]);
-  GetMarkerData.set(view, getMarkerData);
+  const getData = React.useCallback((key) => info.getData(key), [info]);
+  React.useEffect(() => GetMarkerData.set(view, getData), [view, getData]);
 
   // Retrieving data on currently selected function and updating CodeMirror when
   // they have changed.
-  const fct = selection?.current?.fct;
-  const marker = selection?.current?.marker;
-  Text.set(view, useFctText(fct));
-  Fct.set(view, fct);
-  Marker.set(view, marker);
-  Hovered.set(view, hovered?.marker ?? '');
-  Dead.set(view, useFctDead(fct));
-  Callers.set(view, useFctCallers(fct));
-  TaintedLvalues.set(view, useFctTaints(fct));
-  React.useEffect(() => scrollMarkerIntoView(view, marker), [view, marker]);
+  const text = useFctText(fct);
+  React.useEffect(() => Text.set(view, text), [view, text]);
+  // const dead = useFctDead(fct);
+  // React.useEffect(() => Dead.set(view, dead), [view, dead]);
+  // const callers = useFctCallers(fct);
+  // React.useEffect(() => Callers.set(view, callers), [view, callers]);
+  // const taints = useFctTaints(fct);
+  // React.useEffect(() => TaintedLvalues.set(view, taints), [view, taints]);
+
+  // Scrolling the selected marker into view if needed.
+  // React.useEffect(() => scrollMarkerIntoView(view, marker), [view, marker]);
 
   return (
     <>
diff --git a/ivette/src/frama-c/kernel/SourceCode.tsx b/ivette/src/frama-c/kernel/SourceCode.tsx
index 05cb75e067bbb82a96ec061a335b42c1df456c3a..56a8a6a31d777b0b07ec549b1fd226b0abad0de5 100644
--- a/ivette/src/frama-c/kernel/SourceCode.tsx
+++ b/ivette/src/frama-c/kernel/SourceCode.tsx
@@ -45,6 +45,10 @@ import * as Preferences from 'ivette/prefs';
 //  Utilitary types and functions
 // -----------------------------------------------------------------------------
 
+// An alias type for functions and locations.
+type Fct = string | undefined;
+type Marker = string | undefined;
+
 // Recovering the cursor position as a line and a column.
 interface Position { line: number, column: number }
 function getCursorPosition(view: Editor.View): Position {
@@ -61,15 +65,12 @@ function setError(text: string): void {
 }
 
 // Function launching the external editor at the currently selected position.
-interface LaunchEditorProps { view: Editor.View, file: string, command: string }
-async function launchEditor(props: LaunchEditorProps): Promise<void> {
-  const { view, file, command } = props;
-  if (!view || file === '') return;
-  const { line: l, column: c } = getCursorPosition(view);
-  const args = command
+async function editor(file: string, pos: Position, cmd: string): Promise<void> {
+  if (file === '') return;
+  const args = cmd
     .replace('%s', file)
-    .replace('%n', l.toString())
-    .replace('%c', c.toString())
+    .replace('%n', pos.line.toString())
+    .replace('%c', pos.column.toString())
     .split(' ');
   const prog = args.shift(); if (!prog) return;
   const text = `An error has occured when opening the external editor ${prog}`;
@@ -93,11 +94,15 @@ const UpdateSelection = Editor.createField<UpdateSelection>(() => { return; });
 const Source = Editor.createTextField<string>('', (s) => s);
 const File = Editor.createField<string>('');
 
-// const Line = Editor.createLineField();
-
 // This field contains the command use to start the external editor.
 const Command = Editor.createField<string>('');
 
+// This field contains the currently selected function.
+const Fct = Editor.createField<Fct>(undefined);
+
+// This field contains the currently selected marker.
+const Marker = Editor.createField<Marker>(undefined);
+
 // -----------------------------------------------------------------------------
 
 
@@ -115,20 +120,20 @@ function createEventsHandler(): Editor.Extension {
   return Editor.createEventHandler(deps, {
     contextmenu: ({ file, command }, view) => {
       if (file === '') return;
-      const launch = (): Promise<void> => launchEditor({ view, file, command });
       const label = 'Open file in an external editor';
-      Dome.popupMenu([ { label, onClick: launch } ]);
+      const pos = getCursorPosition(view);
+      Dome.popupMenu([ { label, onClick: () => editor(file, pos, command) } ]);
     },
     mouseup: ({ file, command, update }, view, event) => {
       if (file === '') return;
-      const { line, column } = getCursorPosition(view);
+      const pos = getCursorPosition(view);
       Server
-        .send(Ast.getMarkerAt, [file, line, column])
+        .send(Ast.getMarkerAt, [file, pos.line, pos.column])
         .then(([fct, marker]) => {
           if (fct || marker) update({ location: { fct, marker } });
         })
         .catch(() => setError('Failed to request to Frama-C server'));
-      if (event.ctrlKey) launchEditor({ view, file, command });
+      if (event.ctrlKey) editor(file, pos, command);
     },
   });
 }
@@ -158,7 +163,8 @@ function useFctSource(file: string): string {
 
 // Necessary extensions.
 const extensions: Editor.Extension[] = [
-  Source.structure,
+  Source,
+  Editor.Selection,
   Editor.LineNumbers,
   Editor.LanguageHighlighter,
   Editor.HighlightActiveLine,
@@ -182,7 +188,7 @@ export default function SourceCode(): JSX.Element {
   const [fontSize] = Settings.useGlobalSettings(Preferences.EditorFontSize);
   const [command] = Settings.useGlobalSettings(Preferences.EditorCommand);
   const { view, Component } = Editor.Editor(extensions);
-  const [selection, updateSelection] = States.useSelection();
+  const [selection, update] = States.useSelection();
   const marker = selection?.current?.marker;
   const fct = selection?.current?.fct;
   const displayedFct = React.useRef<string | undefined>(undefined);
@@ -191,11 +197,13 @@ export default function SourceCode(): JSX.Element {
   const fctSloc = useFunctionLocation(fct);
   const file = fctSloc?.file ?? '';
   const filename = Path.parse(file).base;
+  const pos = getCursorPosition(view);
+  const source = useFctSource(file);
 
-  Source.set(view, useFctSource(file));
-  UpdateSelection.set(view, updateSelection);
-  Command.set(view, command);
-  File.set(view, file);
+  React.useEffect(() => Source.set(view, source), [view, source]);
+  React.useEffect(() => UpdateSelection.set(view, update), [view, update]);
+  React.useEffect(() => Command.set(view, command), [view, command]);
+  React.useEffect(() => File.set(view, file), [view, file]);
 
   React.useEffect(() => {
     const notDisplayedFct = fct !== displayedFct.current;
@@ -215,7 +223,7 @@ export default function SourceCode(): JSX.Element {
         <Buttons.IconButton
           icon="DUPLICATE"
           visible={file !== ''}
-          onClick={() => launchEditor({ view, file, command })}
+          onClick={() => editor(file, pos, command)}
           title={externalEditorTitle}
         />
         <Labels.Code title={file}>{filename}</Labels.Code>